diff --git a/.rstcheck.cfg b/.rstcheck.cfg index 34613f8ac..daa4ccb0e 100644 --- a/.rstcheck.cfg +++ b/.rstcheck.cfg @@ -1,4 +1,4 @@ [rstcheck] ignore_directives = automodule -ignore_roles = issue,pr +ignore_roles = issue,pr,commit report = warning diff --git a/docs/contributing.rst b/docs/contributing.rst index 7b971d58d..106f6b1dd 100644 --- a/docs/contributing.rst +++ b/docs/contributing.rst @@ -202,10 +202,14 @@ When cutting a new release, follow these steps: #. Commit the changes #. Push the commit to the upstream Github repository (via a PR or not). #. Change to the stable branch and cherry-pick the commit (or merge if appropriate) +#. Run the checks one last time to be sure: ``tox``, #. Tag the commit with ``-s`` to generate a signed tag #. Push the commit to the upstream Github repository with ``git push``, and the new tag with ``git push --tags`` #. Generate a tarball and push to PyPI with the command ``poetry publish --build`` +#. Create `the release on GitHub `_ and copy the + release notes in there, +#. Deploy and announce. Translations diff --git a/docs/release_notes.rst b/docs/release_notes.rst index b4307b008..f1d00414c 100644 --- a/docs/release_notes.rst +++ b/docs/release_notes.rst @@ -4,6 +4,34 @@ Release notes .. towncrier release notes start +v1.2.0 +====== +Released on 2021-05-18. + + +Features +^^^^^^^^ + +* Display the version in the page footer (:issue:`592`). +* Allow sponsors to resign from their position in the group (:issue:`599`). + +Bug Fixes +^^^^^^^^^ + +* Lowercase the username in Forgot Password Ask controller (:issue:`573`). +* Skipped autocomplete in OTP fields (:issue:`593`). + +Contributors +^^^^^^^^^^^^ + +Many thanks to the contributors of bug reports, pull requests, and pull request +reviews for this release: + +* Aurélien Bompard +* Josseline Perdomo +* Yaron Shahrabani + + v1.1.0 ====== @@ -32,8 +60,8 @@ Bug Fixes Documentation Improvements ^^^^^^^^^^^^^^^^^^^^^^^^^^ -* Add rstcheck to check our rst files (:issue:`1c2205f`). -* Update the release docs (:issue:`96b08ea`). +* Add rstcheck to check our rst files (:commit:`1c2205f`). +* Update the release docs (:commit:`96b08ea`). * Fix code-block format in contributing docs (:pr:`595`). Contributors diff --git a/news/573.bug b/news/573.bug new file mode 100644 index 000000000..ff0e7000d --- /dev/null +++ b/news/573.bug @@ -0,0 +1 @@ +Lowercase the username in Forgot Password Ask controller \ No newline at end of file diff --git a/news/592.feature b/news/592.feature new file mode 100644 index 000000000..77564c3d8 --- /dev/null +++ b/news/592.feature @@ -0,0 +1 @@ +Display the version in the page footer diff --git a/news/593.bug b/news/593.bug new file mode 100644 index 000000000..42d415ec8 --- /dev/null +++ b/news/593.bug @@ -0,0 +1 @@ +Skipped autocomplete in OTP fields \ No newline at end of file diff --git a/news/599.feature b/news/599.feature new file mode 100644 index 000000000..b466a18da --- /dev/null +++ b/news/599.feature @@ -0,0 +1 @@ +Allow sponsors to resign from their position in the group diff --git a/news/_template.rst b/news/_template.rst index 2952407cd..b9206cc3f 100644 --- a/news/_template.rst +++ b/news/_template.rst @@ -8,6 +8,7 @@ {%- endif -%} {%- endmacro -%} +Released on {{ versiondata.date }}. This is a {major|feature|bugfix} release that adds [short summary]. {% for section, _ in sections.items() %} diff --git a/news/get-authors.py b/news/get-authors.py index 3024d5c88..ab4e0538e 100755 --- a/news/get-authors.py +++ b/news/get-authors.py @@ -23,7 +23,7 @@ from subprocess import check_output -EXCLUDE = ["dependabot-preview[bot]", "Weblate (bot)"] +EXCLUDE = ["dependabot[bot]", "dependabot-preview[bot]", "Weblate (bot)"] last_tag = check_output( "git tag | sort -n | tail -n 1", shell=True, universal_newlines=True diff --git a/noggin/controller/__init__.py b/noggin/controller/__init__.py index f45ff7a62..634aca7df 100644 --- a/noggin/controller/__init__.py +++ b/noggin/controller/__init__.py @@ -1,5 +1,8 @@ +import os + from flask import Blueprint, g, render_template, session +from noggin import __version__ from noggin.utility.templates import gravatar @@ -13,9 +16,21 @@ def page_not_found(e): @blueprint.app_context_processor def inject_global_template_vars(): + version = __version__ + if ( + "OPENSHIFT_BUILD_COMMIT" in os.environ + and "OPENSHIFT_BUILD_REFERENCE" in os.environ + ): + version_ext = [ + os.environ['OPENSHIFT_BUILD_REFERENCE'], + os.environ['OPENSHIFT_BUILD_COMMIT'][:7], + ] + version = f"{version} ({':'.join(version_ext)})" + return dict( gravatar=gravatar, ipa=g.ipa if 'ipa' in g else None, current_user=g.current_user if 'current_user' in g else None, current_username=session.get('noggin_username'), + noggin_version=version, ) diff --git a/noggin/controller/authentication.py b/noggin/controller/authentication.py index 86b8c4fdd..db4e2b720 100644 --- a/noggin/controller/authentication.py +++ b/noggin/controller/authentication.py @@ -18,7 +18,7 @@ def handle_login_form(form): - username = form.username.data.lower() + username = form.username.data password = form.password.data if form.otp.data: diff --git a/noggin/controller/group.py b/noggin/controller/group.py index 119515533..c9b85a5b6 100644 --- a/noggin/controller/group.py +++ b/noggin/controller/group.py @@ -2,10 +2,10 @@ from flask import flash, g, redirect, render_template, url_for from flask_babel import _ -from noggin.form.add_group_member import AddGroupMemberForm -from noggin.form.remove_group_member import RemoveGroupMemberForm +from noggin.form.group import AddGroupMemberForm, RemoveGroupMemberForm from noggin.representation.group import Group from noggin.representation.user import User +from noggin.security.ipa import raise_on_failed from noggin.utility import messaging from noggin.utility.controllers import group_or_404, with_ipa from noggin.utility.pagination import paginated_find @@ -67,7 +67,8 @@ def group_add_member(ipa, groupname): ) return redirect(url_for('.group', groupname=groupname)) try: - ipa.group_add_member(a_cn=groupname, o_user=username) + result = ipa.group_add_member(a_cn=groupname, o_user=username) + raise_on_failed(result) except python_freeipa.exceptions.ValidationError as e: # e.message is a dict that we have to process ourselves for now: # https://github.com/opennode/python-freeipa/issues/24 @@ -126,12 +127,13 @@ def group_remove_member(ipa, groupname): if form.validate_on_submit(): username = form.username.data try: - ipa.group_remove_member(a_cn=groupname, o_user=username) + result = ipa.group_remove_member(groupname, o_user=username) + raise_on_failed(result) except python_freeipa.exceptions.ValidationError as e: # e.message is a dict that we have to process ourselves for now: # https://github.com/opennode/python-freeipa/issues/24 for error in e.message['member']['user']: - flash('Unable to remove user %s: %s' % (error[0], error[1]), 'danger') + flash(f"Unable to remove user {error[0]}: {error[1]}", "danger") return redirect(url_for('.group', groupname=groupname)) flash_text = _( 'You got it! %(username)s has been removed from %(groupname)s.', @@ -156,6 +158,36 @@ def group_remove_member(ipa, groupname): return redirect(url_for('.group', groupname=groupname)) +@bp.route('/group//sponsors/remove', methods=['POST']) +@with_ipa() +def group_remove_sponsor(ipa, groupname): + group = Group(group_or_404(ipa, groupname)) + # Don't allow removing the last sponsor + if len(group.sponsors) < 2: + flash("Removing the last sponsor is not allowed.", "danger") + return redirect(url_for('.group', groupname=groupname)) + # Only removing onelself from sponsors is allowed + username = g.current_user.username + try: + result = ipa.group_remove_member_manager(groupname, o_user=username) + raise_on_failed(result) + except python_freeipa.exceptions.ValidationError as e: + # e.message is a dict that we have to process ourselves for now: + # https://github.com/opennode/python-freeipa/issues/24 + for error in e.message['membermanager']['user']: + flash(f"Unable to remove user {error[0]}: {error[1]}", "danger") + return redirect(url_for('.group', groupname=groupname)) + flash( + _( + 'You got it! %(username)s is no longer a sponsor of %(groupname)s.', + username=username, + groupname=groupname, + ), + 'success', + ) + return redirect(url_for('.group', groupname=groupname)) + + @bp.route('/groups/') @with_ipa() def groups(ipa): diff --git a/noggin/controller/registration.py b/noggin/controller/registration.py index 437b5dcca..402c626ff 100644 --- a/noggin/controller/registration.py +++ b/noggin/controller/registration.py @@ -44,12 +44,19 @@ def _send_validation_email(user): + ttl = current_app.config["ACTIVATION_TOKEN_EXPIRATION"] token = make_token( {"sub": user.username, "mail": user.mail}, audience=Audience.email_validation, - ttl=current_app.config["ACTIVATION_TOKEN_EXPIRATION"], + ttl=ttl, ) - email_context = {"token": token, "user": user} + valid_until = datetime.datetime.utcnow() + datetime.timedelta(minutes=ttl) + email_context = { + "token": token, + "user": user, + "ttl": ttl, + "valid_until": valid_until, + } email = Message( body=render_template("email-validation.txt", **email_context), html=render_template("email-validation.html", **email_context), diff --git a/noggin/controller/user.py b/noggin/controller/user.py index 6cfe0d96c..f3e978b70 100644 --- a/noggin/controller/user.py +++ b/noggin/controller/user.py @@ -280,7 +280,7 @@ def user_settings_otp_disable(ipa, username): ): flash(_('Sorry, You cannot disable your last active token.'), 'warning') else: - flash('Cannot disable the token.', 'danger') + flash(_('Cannot disable the token.'), 'danger') current_app.logger.error( f'Something went wrong disabling an OTP token for user {username}: {e}' ) diff --git a/noggin/form/base.py b/noggin/form/base.py index 2aa1f0a5b..2cb3836eb 100644 --- a/noggin/form/base.py +++ b/noggin/form/base.py @@ -70,6 +70,10 @@ def strip(value): return value.strip() if value else value +def lower(value): + return value.lower() if value else value + + class CSVListField(Field): widget = TextInput() diff --git a/noggin/form/edit_user.py b/noggin/form/edit_user.py index 5f9adef73..2031336ed 100644 --- a/noggin/form/edit_user.py +++ b/noggin/form/edit_user.py @@ -112,7 +112,7 @@ class UserSettingsAddOTPForm(ModestForm): description=_("please reauthenticate so we know it is you"), ) - otp = PasswordField( + otp = StringField( _('One-Time Password'), validators=[Optional()], description=_("Enter your One-Time Password"), diff --git a/noggin/form/add_group_member.py b/noggin/form/group.py similarity index 58% rename from noggin/form/add_group_member.py rename to noggin/form/group.py index 9dfef2f9a..4ac076c93 100644 --- a/noggin/form/add_group_member.py +++ b/noggin/form/group.py @@ -1,5 +1,5 @@ from flask_babel import lazy_gettext as _ -from wtforms import StringField +from wtforms import HiddenField, StringField from wtforms.validators import DataRequired from .base import BaseForm @@ -10,3 +10,10 @@ class AddGroupMemberForm(BaseForm): 'New Member Username', validators=[DataRequired(message=_('New member username must not be empty'))], ) + + +class RemoveGroupMemberForm(BaseForm): + username = HiddenField( + _('Username'), + validators=[DataRequired(message=_('Username must not be empty'))], + ) diff --git a/noggin/form/login_user.py b/noggin/form/login_user.py index 250b3e98f..4dd712280 100644 --- a/noggin/form/login_user.py +++ b/noggin/form/login_user.py @@ -3,12 +3,16 @@ from wtforms.validators import DataRequired, Optional from .base import ModestForm, SubmitButtonField +from .validators import no_mixed_case class LoginUserForm(ModestForm): username = StringField( _('Username'), - validators=[DataRequired(message=_('You must provide a user name'))], + validators=[ + DataRequired(message=_('You must provide a user name')), + no_mixed_case, + ], ) password = PasswordField( diff --git a/noggin/form/password_reset.py b/noggin/form/password_reset.py index 5e10b5e57..e019baac2 100644 --- a/noggin/form/password_reset.py +++ b/noggin/form/password_reset.py @@ -2,7 +2,7 @@ from wtforms import PasswordField, StringField from wtforms.validators import DataRequired, EqualTo, Optional -from .base import BaseForm +from .base import BaseForm, lower from .validators import PasswordLength @@ -36,4 +36,5 @@ class ForgottenPasswordForm(BaseForm): _('Username'), validators=[DataRequired(message=_('User name must not be empty'))], description=_("Enter your username to reset your password"), + filters=[lower], ) diff --git a/noggin/form/register_user.py b/noggin/form/register_user.py index 832c8b96c..8e3b7fb77 100644 --- a/noggin/form/register_user.py +++ b/noggin/form/register_user.py @@ -3,7 +3,7 @@ from wtforms.fields.html5 import EmailField from wtforms.validators import DataRequired, EqualTo -from noggin.form.validators import Email, PasswordLength +from noggin.form.validators import Email, no_mixed_case, PasswordLength from .base import BaseForm, ModestForm, strip, SubmitButtonField @@ -23,7 +23,10 @@ class RegisterUserForm(ModestForm): username = StringField( _('Username'), - validators=[DataRequired(message=_('User name must not be empty'))], + validators=[ + DataRequired(message=_('User name must not be empty')), + no_mixed_case, + ], filters=[strip], ) diff --git a/noggin/form/remove_group_member.py b/noggin/form/remove_group_member.py deleted file mode 100644 index cd4902490..000000000 --- a/noggin/form/remove_group_member.py +++ /dev/null @@ -1,12 +0,0 @@ -from flask_babel import lazy_gettext as _ -from wtforms import HiddenField -from wtforms.validators import DataRequired - -from .base import BaseForm - - -class RemoveGroupMemberForm(BaseForm): - username = HiddenField( - _('Username'), - validators=[DataRequired(message=_('Username must not be empty'))], - ) diff --git a/noggin/form/validators.py b/noggin/form/validators.py index d7e523a46..335523883 100644 --- a/noggin/form/validators.py +++ b/noggin/form/validators.py @@ -30,3 +30,8 @@ def __call__(self, form, field): message=self.message, ) validator(form, field) + + +def no_mixed_case(form, field): + if field.data != field.data.lower(): + raise ValidationError(_("Mixed case is not allowed, try lower case.")) diff --git a/noggin/security/ipa.py b/noggin/security/ipa.py index f013fc0a5..c9f8c9838 100644 --- a/noggin/security/ipa.py +++ b/noggin/security/ipa.py @@ -3,7 +3,7 @@ import python_freeipa from cryptography.fernet import Fernet from python_freeipa.client_meta import ClientMeta as IPAClient -from python_freeipa.exceptions import BadRequest +from python_freeipa.exceptions import BadRequest, ValidationError from requests import RequestException @@ -112,6 +112,17 @@ def fasagreement_disable(self, agreement, **kwargs): self._request('fasagreement_disable', agreement, kwargs) +def raise_on_failed(result): + failed = result.get("failed", {}) + num_failed = sum( + sum(len(failures) for failures in object_types.values()) + for object_types in failed.values() + ) + if num_failed == 0: + return # no actual failure + raise ValidationError(failed) + + # Construct an IPA client from app config, but don't attempt to log in with it # or to form a session of any kind with it. This is useful for one-off cases # like password resets where a session isn't actually required. diff --git a/noggin/templates/_login_form.html b/noggin/templates/_login_form.html index e7f7cac24..db5eaa9c6 100644 --- a/noggin/templates/_login_form.html +++ b/noggin/templates/_login_form.html @@ -9,7 +9,7 @@ {{ macros.with_errors(login_form.password, class="validate", placeholder="Password", tabindex="2", label=False) }}
- {{ macros.with_errors(login_form.otp, class="validate", placeholder="One-Time Password (if you have one)", tabindex="3", label=False) }} + {{ macros.with_errors(login_form.otp, class="validate", placeholder="One-Time Password (if you have one)", tabindex="3", autocomplete="off", label=False) }}
{% if lost_otp_token is not defined %} diff --git a/noggin/templates/forgot-password-change.html b/noggin/templates/forgot-password-change.html index 6564fe3f4..f805ad2c0 100644 --- a/noggin/templates/forgot-password-change.html +++ b/noggin/templates/forgot-password-change.html @@ -16,7 +16,7 @@
{{ _('Password Reset for %(username)s', username=username) }}
{{ macros.with_errors(form.password, tabindex="1")}}
{{ macros.with_errors(form.password_confirm, tabindex="2")}}
-
{{ macros.with_errors(form.otp, tabindex="3")}}
+
{{ macros.with_errors(form.otp, tabindex="3", autocomplete="off")}}
+ + {% endfor %} + + {% endif %}
diff --git a/noggin/templates/password-reset.html b/noggin/templates/password-reset.html index 0108e2475..83646544d 100644 --- a/noggin/templates/password-reset.html +++ b/noggin/templates/password-reset.html @@ -18,7 +18,7 @@
{{ _('Expired Password Reset for %(username)s', username=us
{{ macros.with_errors(password_reset_form.password, tabindex="3")}}
{{ macros.with_errors(password_reset_form.password_confirm, tabindex="4")}}
{% if tokens %} -
{{ macros.with_errors(password_reset_form.otp, tabindex="5")}}
+
{{ macros.with_errors(password_reset_form.otp, tabindex="5", autocomplete="off")}}
{% endif %}
diff --git a/noggin/themes/fas/templates/email-validation.html b/noggin/themes/fas/templates/email-validation.html index e48af10af..3648821d2 100644 --- a/noggin/themes/fas/templates/email-validation.html +++ b/noggin/themes/fas/templates/email-validation.html @@ -6,6 +6,13 @@ {{ url_for('.activate_account', _external=True) }}?token={{ token }}

+

+ {{_("This link will be valid for %(ttl)s minutes (until %(valid_until)s UTC).", ttl=ttl, valid_until=valid_until.strftime("%H:%M"))}} + {{_("If the link has expired, you can request a new one here: ")}} + + {{ url_for('.confirm_registration', _external=True) }}?username={{ user.username }} + +

{{_("If you did not create an account for username %(username)s, you can ignore this email.", username=user.username)}}

{{_("Fedora Accounts System")}}

diff --git a/noggin/themes/fas/templates/email-validation.txt b/noggin/themes/fas/templates/email-validation.txt index fc8119663..978fe8519 100644 --- a/noggin/themes/fas/templates/email-validation.txt +++ b/noggin/themes/fas/templates/email-validation.txt @@ -6,6 +6,11 @@ {{ url_for('.activate_account', _external=True) }}?token={{ token }} +{{_("This link will be valid for %(ttl)s minutes (until %(valid_until)s UTC).", ttl=ttl, valid_until=valid_until.strftime("%H:%M"))}} +{{_("If the link has expired, you can request a new one here:")}} + + {{ url_for('.confirm_registration', _external=True) }}?username={{ user.username }} + {{_("If you did not create an account for username %(username)s, you can ignore this email.", username=user.username)}} -- {{_("Fedora Accounts System")}} diff --git a/noggin/themes/fas/templates/main.html b/noggin/themes/fas/templates/main.html index 627baf344..cd6ab9580 100644 --- a/noggin/themes/fas/templates/main.html +++ b/noggin/themes/fas/templates/main.html @@ -68,49 +68,56 @@ {% block footer %} {% endblock %} diff --git a/noggin/themes/openSUSE/templates/email-validation.html b/noggin/themes/openSUSE/templates/email-validation.html index d24b1efe3..c98863bcd 100644 --- a/noggin/themes/openSUSE/templates/email-validation.html +++ b/noggin/themes/openSUSE/templates/email-validation.html @@ -6,6 +6,13 @@ {{ url_for('.activate_account', _external=True) }}?token={{ token }}

+

+ {{_("This link will be valid for %(ttl)s minutes (until %(valid_until)s UTC).", ttl=ttl, valid_until=valid_until.strftime("%H:%M"))}} + {{_("If the link has expired, you can request a new one here: ")}} + + {{ url_for('.confirm_registration', _external=True) }}?username={{ user.username }} + +

{{_("If you did not create an account for username %(username)s, you can ignore this email.", username=user.username)}}

{{_("openSUSE Admins")}}

diff --git a/noggin/themes/openSUSE/templates/email-validation.txt b/noggin/themes/openSUSE/templates/email-validation.txt index b86ff733a..e1e59af3e 100644 --- a/noggin/themes/openSUSE/templates/email-validation.txt +++ b/noggin/themes/openSUSE/templates/email-validation.txt @@ -6,6 +6,11 @@ {{ url_for('.activate_account', _external=True) }}?token={{ token }} +{{_("This link will be valid for %(ttl)s minutes (until %(valid_until)s UTC).", ttl=ttl, valid_until=valid_until.strftime("%H:%M"))}} +{{_("If the link has expired, you can request a new one here:")}} + + {{ url_for('.confirm_registration', _external=True) }}?username={{ user.username }} + {{_("If you did not create an account for username %(username)s, you can ignore this email.", username=user.username)}} -- {{_("openSUSE Admins")}} diff --git a/noggin/themes/openSUSE/templates/main.html b/noggin/themes/openSUSE/templates/main.html index f527726c0..8b0d95638 100644 --- a/noggin/themes/openSUSE/templates/main.html +++ b/noggin/themes/openSUSE/templates/main.html @@ -72,7 +72,7 @@ {% set noggin_link %} noggin {% endset %} -
{{_("Powered by %(noggin_link)s", noggin_link=noggin_link)}}
+
{{_("Powered by %(noggin_link)s", noggin_link=noggin_link)}} v{{ noggin_version }}
{{ ipa.ipa_version|default('') }}
diff --git a/noggin/translations/he/LC_MESSAGES/messages.po b/noggin/translations/he/LC_MESSAGES/messages.po new file mode 100644 index 000000000..0e9bab9a5 --- /dev/null +++ b/noggin/translations/he/LC_MESSAGES/messages.po @@ -0,0 +1,700 @@ +# Translations template for PROJECT. +# Copyright (C) 2020 ORGANIZATION +# This file is distributed under the same license as the PROJECT project. +# FIRST AUTHOR , 2020. +# Yaron Shahrabani , 2021. +msgid "" +msgstr "" +"Project-Id-Version: PROJECT VERSION\n" +"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" +"POT-Creation-Date: 2020-04-08 15:35+0000\n" +"PO-Revision-Date: 2021-05-05 11:02+0000\n" +"Last-Translator: Yaron Shahrabani \n" +"Language-Team: Hebrew \n" +"Language: he\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 == 2) ? 1 : ((n > 10 && " +"n % 10 == 0) ? 2 : 3));\n" +"X-Generator: Weblate 4.6.1\n" +"Generated-By: Babel 2.8.0\n" + +#: noggin/controller/authentication.py:20 +msgid "Password expired. Please reset it." +msgstr "תוקף הססמה פג. נא לאפס אותה." + +#: noggin/controller/authentication.py:31 +#: noggin/controller/authentication.py:38 +msgid "Could not log in to the IPA server." +msgstr "לא ניתן להיכנס לשרת ה־IPA." + +#: noggin/controller/authentication.py:40 +#, python-format +msgid "Welcome, %(username)s!" +msgstr "ברוך בואך, %(username)s!" + +#: noggin/controller/authentication.py:59 +msgid "Token successfully synchronized" +msgstr "האסימון סונכרן בהצלחה" + +#: noggin/controller/group.py:57 +#, python-format +msgid "User %(username)s was not found in the system." +msgstr "המשתמש %(username)s לא נמצא במערכת." + +#: noggin/controller/group.py:68 +#, python-format +msgid "Unable to add user %(username)s: %(errormessage)s" +msgstr "לא ניתן להוסיף את המשתמש %(username)s:‏ %(errormessage)s" + +#: noggin/controller/group.py:78 +#, python-format +msgid "You got it! %(username)s has been added to %(groupname)s." +msgstr "בוצע! %(username)s התווסף אל %(groupname)s." + +#: noggin/controller/group.py:121 +#, python-format +msgid "You got it! %(username)s has been removed from %(groupname)s." +msgstr "בוצע! %(username)s הוסר מתוך %(groupname)s." + +#: noggin/controller/password.py:42 +msgid "The old password or username is not correct" +msgstr "הססמה הישנה או שם המשתמשים שגויים" + +#: noggin/controller/password.py:53 +msgid "Could not change password." +msgstr "לא ניתן להחליף ססמה." + +#: noggin/controller/password.py:56 +msgid "Your password has been changed" +msgstr "הססמה שלך הוחלפה" + +#: noggin/controller/password.py:118 +#, python-format +msgid "" +"You have already requested a password reset, you need to wait " +"%(wait_min)s minute(s) and %(wait_sec)s seconds before you can request " +"another." +msgstr "" +"כבר ביקשת לאפס את הססמה, עליך להמתין %(wait_min)s דקות ו־%(wait_sec)s שניות " +"לפני הגשת בקשה נוספת." + +#: noggin/controller/password.py:130 +#, python-format +msgid "User %(username)s does not exist" +msgstr "המשתמש %(username)s לא קיים" + +#: noggin/controller/password.py:145 +msgid "We could not send you an email, please retry later" +msgstr "לא הצלחנו לשלוח לך הודעה בדוא״ל, נא לנסות שוב מאוחר יותר" + +#: noggin/controller/password.py:151 +msgid "" +"An email has been sent to your address with instructions on how to reset " +"your password" +msgstr "נשלחה הודעת דוא״ל לכתובת שלך עם הנחיות כיצד לאפס את הססמה שלך" + +#: noggin/controller/password.py:170 +msgid "The token is invalid, please request a new one." +msgstr "האסימון שגוי, נא לבקש אחד חדש." + +#: noggin/controller/password.py:178 +msgid "The token has expired, please request a new one." +msgstr "תוקף האסימון פג, נא לבקש אחד חדש." + +#: noggin/controller/password.py:184 +msgid "" +"Your password has been changed since you requested this token, please " +"request a new one." +msgstr "הססמה שלך הוחלפה מאז שביקשת אסימון, נא לבקש אחת חדשה." + +#: noggin/controller/password.py:215 +#, python-format +msgid "" +"Your password has been changed, but it does not comply with the policy " +"(%(policy_error)s) and has thus been set as expired. You will be asked to" +" change it after logging in." +msgstr "" + +#: noggin/controller/password.py:240 +msgid "Incorrect value." +msgstr "" + +#: noggin/controller/password.py:248 +msgid "Could not change password, please try again." +msgstr "" + +#: noggin/controller/password.py:252 +msgid "Your password has been changed." +msgstr "" + +#: noggin/controller/registration.py:73 +msgid "An error occurred while creating the account, please try again." +msgstr "" + +#: noggin/controller/registration.py:88 +#, python-format +msgid "" +"Your account has been created, but the password you chose does not comply" +" with the policy (%(policy_error)s) and has thus been set as expired. You" +" will be asked to change it after logging in." +msgstr "" + +#: noggin/controller/registration.py:107 +#, python-format +msgid "" +"Your account has been created, but an error occurred while setting your " +"password (%(message)s). You may need to change it after logging in." +msgstr "" + +#: noggin/controller/registration.py:117 +msgid "Congratulations, you now have an account! Go ahead and sign in to proceed." +msgstr "" + +#: noggin/controller/user.py:157 +msgid "Incorrect password" +msgstr "" + +#: noggin/controller/user.py:162 +msgid "Cannot create the token." +msgstr "" + +#: noggin/controller/user.py:197 +msgid "Sorry, You cannot disable your last active token." +msgstr "" + +#: noggin/controller/user.py:204 +msgid "Cannot disable the token." +msgstr "" + +#: noggin/controller/user.py:231 +msgid "Sorry, You cannot delete your last active token." +msgstr "" + +#: noggin/controller/user.py:233 noggin/controller/user.py:238 +msgid "Cannot delete the token." +msgstr "" + +#: noggin/form/add_group_member.py:10 +msgid "New member username must not be empty" +msgstr "" + +#: noggin/form/edit_user.py:20 noggin/form/register_user.py:11 +msgid "First Name" +msgstr "" + +#: noggin/form/edit_user.py:21 noggin/form/register_user.py:12 +msgid "First name must not be empty" +msgstr "" + +#: noggin/form/edit_user.py:25 noggin/form/register_user.py:17 +msgid "Last Name" +msgstr "" + +#: noggin/form/edit_user.py:26 noggin/form/register_user.py:18 +msgid "Last name must not be empty" +msgstr "" + +#: noggin/form/edit_user.py:30 noggin/form/register_user.py:41 +msgid "E-mail Address" +msgstr "" + +#: noggin/form/edit_user.py:32 noggin/form/register_user.py:43 +msgid "Email must not be empty" +msgstr "" + +#: noggin/form/edit_user.py:33 noggin/form/register_user.py:44 +msgid "Email must be valid" +msgstr "" + +#: noggin/form/edit_user.py:38 noggin/templates/user.html:38 +msgid "Locale" +msgstr "" + +#: noggin/form/edit_user.py:41 +msgid "Locale must not be empty" +msgstr "" + +#: noggin/form/edit_user.py:42 +msgid "Locale must be a valid locale short-code" +msgstr "" + +#: noggin/form/edit_user.py:46 noggin/templates/user.html:35 +msgid "IRC Nickname" +msgstr "" + +#: noggin/form/edit_user.py:49 noggin/templates/user.html:32 +msgid "Timezone" +msgstr "" + +#: noggin/form/edit_user.py:52 +msgid "Timezone must not be empty" +msgstr "" + +#: noggin/form/edit_user.py:53 +msgid "Timezone must be a valid timezone" +msgstr "" + +#: noggin/form/edit_user.py:57 +msgid "GitHub Username" +msgstr "" + +#: noggin/form/edit_user.py:59 +msgid "GitLab Username" +msgstr "" + +#: noggin/form/edit_user.py:61 +msgid "Red Hat Bugzilla Email" +msgstr "" + +#: noggin/form/edit_user.py:67 +msgid "SSH Keys" +msgstr "" + +#: noggin/form/edit_user.py:71 noggin/templates/user.html:41 +msgid "GPG Keys" +msgstr "" + +#: noggin/form/edit_user.py:77 +msgid "Token description" +msgstr "" + +#: noggin/form/edit_user.py:78 +msgid "Description must not be empty" +msgstr "" + +#: noggin/form/edit_user.py:82 +msgid "Enter your current password" +msgstr "" + +#: noggin/form/edit_user.py:83 noggin/form/login_user.py:16 +#: noggin/form/sync_token.py:15 +msgid "You must provide a password" +msgstr "" + +#: noggin/form/edit_user.py:89 noggin/form/edit_user.py:95 +msgid "token must not be empty" +msgstr "" + +#: noggin/form/login_user.py:10 noggin/form/password_reset.py:36 +#: noggin/form/register_user.py:23 noggin/form/remove_group_member.py:9 +#: noggin/form/sync_token.py:9 noggin/templates/sync-token.html:16 +msgid "Username" +msgstr "" + +#: noggin/form/login_user.py:11 noggin/form/sync_token.py:10 +msgid "You must provide a user name" +msgstr "" + +#: noggin/form/login_user.py:15 noggin/form/register_user.py:29 +#: noggin/form/sync_token.py:14 noggin/templates/sync-token.html:19 +#: noggin/templates/user-settings.html:28 +msgid "Password" +msgstr "" + +#: noggin/form/login_user.py:19 +msgid "Log In" +msgstr "" + +#: noggin/form/password_reset.py:10 +msgid "New Password" +msgstr "" + +#: noggin/form/password_reset.py:12 noggin/form/register_user.py:31 +msgid "Password must not be empty" +msgstr "" + +#: noggin/form/password_reset.py:13 noggin/form/register_user.py:32 +msgid "Passwords must match" +msgstr "" + +#: noggin/form/password_reset.py:17 +msgid "Confirm New Password" +msgstr "" + +#: noggin/form/password_reset.py:20 +msgid "OTP Token" +msgstr "" + +#: noggin/form/password_reset.py:20 +msgid "Enter your OTP token if you have enrolled one" +msgstr "" + +#: noggin/form/password_reset.py:27 +msgid "Current Password" +msgstr "" + +#: noggin/form/password_reset.py:28 +msgid "Current password must not be empty" +msgstr "" + +#: noggin/form/password_reset.py:29 +msgid "Just the password, don't add the OTP token if you have one" +msgstr "" + +#: noggin/form/password_reset.py:37 noggin/form/register_user.py:24 +msgid "User name must not be empty" +msgstr "" + +#: noggin/form/password_reset.py:38 +msgid "Enter your username to reset your password" +msgstr "" + +#: noggin/form/register_user.py:35 +msgid "Please choose a strong password" +msgstr "" + +#: noggin/form/register_user.py:38 +msgid "Confirm Password" +msgstr "" + +#: noggin/form/register_user.py:49 noggin/templates/index.html:19 +msgid "Register" +msgstr "" + +#: noggin/form/remove_group_member.py:10 +msgid "Username must not be empty" +msgstr "" + +#: noggin/form/sync_token.py:19 noggin/templates/sync-token.html:22 +msgid "First OTP" +msgstr "" + +#: noggin/form/sync_token.py:20 +msgid "You must provide a first code" +msgstr "" + +#: noggin/form/sync_token.py:24 noggin/templates/sync-token.html:25 +msgid "Second OTP" +msgstr "" + +#: noggin/form/sync_token.py:25 +msgid "You must provide a second code" +msgstr "" + +#: noggin/form/sync_token.py:28 noggin/templates/sync-token.html:28 +msgid "Token ID" +msgstr "" + +#: noggin/templates/404.html:3 +msgid "You've ruined everything." +msgstr "" + +#: noggin/templates/404.html:10 +msgid "That page wasn't found. You've gone and ruined everything." +msgstr "" + +#: noggin/templates/_login_form.html:11 +msgid "Forgot password?" +msgstr "" + +#: noggin/templates/_login_form.html:13 +msgid "Forgotten password or lost OTP token?" +msgstr "" + +#: noggin/templates/_login_form.html:16 +msgid "Sync Token" +msgstr "" + +#: noggin/templates/forgot-password-ask.html:2 +msgid "Password Recovery" +msgstr "" + +#: noggin/templates/forgot-password-ask.html:16 +msgid "Did you forget your password?" +msgstr "" + +#: noggin/templates/forgot-password-ask.html:17 +msgid "" +"Enter your username and an email will be sent to your address with " +"further instructions." +msgstr "" + +#: noggin/templates/forgot-password-ask.html:22 +msgid "Send" +msgstr "" + +#: noggin/templates/forgot-password-change.html:2 +#: noggin/templates/forgot-password-change.html:23 +msgid "Reset Password" +msgstr "" + +#: noggin/templates/forgot-password-change.html:16 +#, python-format +msgid "Password Reset for %(username)s" +msgstr "" + +#: noggin/templates/group.html:5 +#, python-format +msgid "%(groupname)s Group" +msgstr "" + +#: noggin/templates/group.html:31 +msgid "To join this group, contact a group sponsor." +msgstr "" + +#: noggin/templates/group.html:38 +msgid "Sponsors" +msgstr "" + +#: noggin/templates/group.html:42 +msgid "no sponsors" +msgstr "" + +#: noggin/templates/group.html:68 +msgid "Members" +msgstr "" + +#: noggin/templates/group.html:75 +msgid "add user..." +msgstr "" + +#: noggin/templates/group.html:83 +msgid "No members yet." +msgstr "" + +#: noggin/templates/groups.html:5 noggin/templates/groups.html:12 +msgid "Group List" +msgstr "" + +#: noggin/templates/groups.html:30 +#, python-format +msgid "%(member_count)s members" +msgstr "" + +#: noggin/templates/index.html:16 noggin/templates/login.html:2 +msgid "Login" +msgstr "" + +#: noggin/templates/password-reset.html:2 +msgid "Expired Password Reset" +msgstr "" + +#: noggin/templates/password-reset.html:15 +#, python-format +msgid "Expired Password Reset for %(username)s" +msgstr "" + +#: noggin/templates/password-reset.html:24 +#: noggin/templates/user-settings-password.html:7 +#: noggin/templates/user-settings-password.html:16 +msgid "Change Password" +msgstr "" + +#: noggin/templates/register.html:2 +msgid "Registration" +msgstr "" + +#: noggin/templates/sync-token.html:2 +msgid "Sync OTP Token" +msgstr "" + +#: noggin/templates/sync-token.html:10 +msgid "Synchronize OTP Token" +msgstr "" + +#: noggin/templates/sync-token.html:33 +msgid "Sync" +msgstr "" + +#: noggin/templates/user-settings-keys.html:8 +msgid "GPG Key ID" +msgstr "" + +#: noggin/templates/user-settings-keys.html:9 +msgid "SSH Public Key" +msgstr "" + +#: noggin/templates/user-settings-keys.html:13 +#: noggin/templates/user-settings-profile.html:22 +msgid "Save" +msgstr "" + +#: noggin/templates/user-settings-otp.html:11 +msgid "Scan your new token" +msgstr "" + +#: noggin/templates/user-settings-otp.html:18 +msgid "" +"Your new token is ready. Click on the button below to reveal the QR code " +"and scan it." +msgstr "" + +#: noggin/templates/user-settings-otp.html:19 +msgid "Reveal" +msgstr "" + +#: noggin/templates/user-settings-otp.html:21 +msgid "or copy and paste the following token URL if you can't scan the QR code:" +msgstr "" + +#: noggin/templates/user-settings-otp.html:23 +msgid "" +"This will never be shown to you again, don't close this window until your" +" token is saved." +msgstr "" + +#: noggin/templates/user-settings-otp.html:31 +msgid "OTP Tokens" +msgstr "" + +#: noggin/templates/user-settings-otp.html:33 +msgid "Add OTP Token" +msgstr "" + +#: noggin/templates/user-settings-otp.html:38 +msgid "Password or Password + One-Time-Password" +msgstr "" + +#: noggin/templates/user-settings-otp.html:40 +msgid "Generate" +msgstr "" + +#: noggin/templates/user-settings-otp.html:59 +msgid "Disable" +msgstr "" + +#: noggin/templates/user-settings-otp.html:62 +msgid "Disabled" +msgstr "" + +#: noggin/templates/user-settings-otp.html:72 +msgid "You have no OTP tokens" +msgstr "" + +#: noggin/templates/user-settings.html:3 noggin/templates/user-settings.html:14 +#, python-format +msgid "Settings for %(username)s" +msgstr "" + +#: noggin/templates/user-settings.html:19 noggin/templates/user.html:21 +#: noggin/themes/default/templates/main.html:25 +#: noggin/themes/fas/templates/main.html:27 +msgid "Profile" +msgstr "" + +#: noggin/templates/user-settings.html:22 +msgid "SSH & GPG Keys" +msgstr "" + +#: noggin/templates/user-settings.html:25 +msgid "OTP" +msgstr "" + +#: noggin/templates/user.html:3 +#, python-format +msgid "Profile for %(username)s" +msgstr "" + +#: noggin/templates/user.html:24 noggin/themes/default/templates/main.html:17 +#: noggin/themes/fas/templates/main.html:19 +msgid "Groups" +msgstr "" + +#: noggin/templates/user.html:44 +msgid "RHBZ E-Mail" +msgstr "" + +#: noggin/templates/user.html:62 noggin/themes/default/templates/main.html:26 +#: noggin/themes/fas/templates/main.html:28 +msgid "Settings" +msgstr "" + +#: noggin/templates/user.html:86 +msgid "sponsor" +msgstr "" + +#: noggin/templates/user.html:86 +msgid "member" +msgstr "" + +#: noggin/themes/default/templates/forgot-password-email.html:2 +#: noggin/themes/fas/templates/forgot-password-email.html:2 +#: noggin/themes/openSUSE/templates/forgot-password-email.html:2 +msgid "To reset your password, click on the link below:" +msgstr "" + +#: noggin/themes/default/templates/forgot-password-email.html:8 +#: noggin/themes/fas/templates/forgot-password-email.html:8 +#: noggin/themes/openSUSE/templates/forgot-password-email.html:8 +msgid "" +"If you did not request your password to be reset, you can ignore this " +"email." +msgstr "" + +#: noggin/themes/default/templates/forgot-password-email.html:10 +msgid "The Noggin team" +msgstr "" + +#: noggin/themes/default/templates/main.html:14 +#: noggin/themes/fas/templates/main.html:16 +msgid "search..." +msgstr "" + +#: noggin/themes/default/templates/main.html:27 +#: noggin/themes/fas/templates/main.html:29 +msgid "Log Out" +msgstr "" + +#: noggin/themes/default/templates/main.html:61 +#: noggin/themes/fas/templates/main.html:63 +#, python-format +msgid "Powered by %(noggin_link)s" +msgstr "" + +#: noggin/themes/default/templates/main.html:77 +msgid "Welcome to noggin!" +msgstr "" + +#: noggin/themes/default/templates/main.html:79 +msgid "" +"This is the open source, community self-service portal for FreeIPA. It " +"allows you to do things like create an account, change your password, " +"manage group membership, and more." +msgstr "" + +#: noggin/themes/fas/templates/main.html:88 +msgid "Fedora Accounts" +msgstr "" + +#: noggin/themes/fas/templates/main.html:90 +msgid "" +"Fedora Accounts allows you to create and manage an account for Fedora " +"Tools and Infrastructure." +msgstr "" + +#: noggin/themes/fas/templates/main.html:100 +msgid "file a Fedora Infra ticket to change the details or sponsors of this group" +msgstr "" + +#: noggin/themes/fas/templates/main.html:101 +msgid "Request Change of Details" +msgstr "" + +#: noggin/themes/fas/templates/main.html:113 +msgid "Create a PDR request to disable your account" +msgstr "" + +#: noggin/themes/fas/templates/main.html:114 +msgid "Request account deletion" +msgstr "" + +#: noggin/themes/fas/templates/main.html:125 +msgid "Did you lose your OTP token?" +msgstr "" + +#: noggin/themes/fas/templates/main.html:129 +#, python-format +msgid "" +"If you have lost your OTP token you need to send an email to " +"%(admin_email)s. Please sign this email using the GPG key associated with" +" your account if possible, so that the administrator can verify your " +"identity." +msgstr "" + +#: noggin/utility/__init__.py:66 +#, python-format +msgid "Group %(groupname)s could not be found." +msgstr "" diff --git a/noggin/utility/password_reset.py b/noggin/utility/password_reset.py index b3f7402fb..64e90ce50 100644 --- a/noggin/utility/password_reset.py +++ b/noggin/utility/password_reset.py @@ -27,7 +27,10 @@ def store(self): open(file_path, "w").close() def delete(self): - os.remove(self._get_file_path()) + try: + os.remove(self._get_file_path()) + except FileNotFoundError: + pass # It's already been removed def _get_file_path(self): base_dir = current_app.config["PASSWORD_RESET_LOCK_DIR"] diff --git a/poetry.lock b/poetry.lock index 038f15bc5..49b2c9528 100644 --- a/poetry.lock +++ b/poetry.lock @@ -24,17 +24,17 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" [[package]] name = "attrs" -version = "20.3.0" +version = "21.2.0" description = "Classes Without Boilerplate" category = "main" 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.extras] -dev = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface", "furo", "sphinx", "pre-commit"] -docs = ["furo", "sphinx", "zope.interface"] -tests = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface"] -tests_no_zope = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six"] +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 = "automat" @@ -199,16 +199,19 @@ category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4" +[package.dependencies] +toml = {version = "*", optional = true, markers = "extra == \"toml\""} + [package.extras] toml = ["toml"] [[package]] name = "crochet" -version = "1.12.0" +version = "2.0.0" description = "Use Twisted anywhere!" category = "main" optional = false -python-versions = "*" +python-versions = ">=3.6.0" [package.dependencies] Twisted = ">=16.0" @@ -282,7 +285,7 @@ text-unidecode = "1.3" [[package]] name = "fedora-messaging" -version = "2.0.2" +version = "2.1.0" description = "A set of tools for using Fedora's messaging infrastructure" category = "main" optional = false @@ -303,7 +306,7 @@ Twisted = "*" [[package]] name = "flake8" -version = "3.9.1" +version = "3.9.2" description = "the modular source code checker: pep8 pyflakes and co" category = "dev" optional = false @@ -317,17 +320,17 @@ pyflakes = ">=2.3.0,<2.4.0" [[package]] name = "flask" -version = "1.1.2" +version = "1.1.4" description = "A simple framework for building complex web applications." category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" [package.dependencies] -click = ">=5.1" -itsdangerous = ">=0.24" -Jinja2 = ">=2.10.1" -Werkzeug = ">=0.15" +click = ">=5.1,<8.0" +itsdangerous = ">=0.24,<2.0" +Jinja2 = ">=2.10.1,<3.0" +Werkzeug = ">=0.15,<2.0" [package.extras] dev = ["pytest", "coverage", "tox", "sphinx", "pallets-sphinx-themes", "sphinxcontrib-log-cabinet", "sphinx-issues"] @@ -408,14 +411,15 @@ smmap = ">=3.0.1,<5" [[package]] name = "gitpython" -version = "3.1.14" +version = "3.1.17" description = "Python Git Library" category = "dev" optional = false -python-versions = ">=3.4" +python-versions = ">=3.5" [package.dependencies] gitdb = ">=4.0.1,<5" +typing-extensions = {version = ">=3.7.4.0", markers = "python_version < \"3.8\""} [[package]] name = "gunicorn" @@ -701,7 +705,7 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" [[package]] name = "pygments" -version = "2.8.1" +version = "2.9.0" description = "Pygments is a syntax highlighting package written in Python." category = "dev" optional = false @@ -785,14 +789,14 @@ testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "requests", "xm [[package]] name = "pytest-cov" -version = "2.11.1" +version = "2.12.0" 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" +coverage = {version = ">=5.2.1", extras = ["toml"]} pytest = ">=4.6" [package.extras] @@ -800,7 +804,7 @@ testing = ["fields", "hunter", "process-tests (==2.0.2)", "six", "pytest-xdist", [[package]] name = "pytest-mock" -version = "3.6.0" +version = "3.6.1" description = "Thin-wrapper around the mock package for easier use with pytest" category = "dev" optional = false @@ -914,27 +918,28 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" [[package]] name = "service-identity" -version = "18.1.0" +version = "21.1.0" description = "Service identity verification for pyOpenSSL & cryptography." category = "main" optional = false python-versions = "*" [package.dependencies] -attrs = ">=16.0.0" +attrs = ">=19.1.0" cryptography = "*" pyasn1 = "*" pyasn1-modules = "*" +six = "*" [package.extras] -dev = ["coverage (>=4.2.0)", "pytest", "sphinx", "idna", "pyopenssl"] -docs = ["sphinx"] +dev = ["coverage[toml] (>=5.0.2)", "pytest", "sphinx", "furo", "idna", "pyopenssl"] +docs = ["sphinx", "furo"] idna = ["idna"] -tests = ["coverage (>=4.2.0)", "pytest"] +tests = ["coverage[toml] (>=5.0.2)", "pytest"] [[package]] name = "six" -version = "1.15.0" +version = "1.16.0" description = "Python 2 and 3 compatibility utilities" category = "main" optional = false @@ -1151,7 +1156,7 @@ python-versions = "*" [[package]] name = "typing-extensions" -version = "3.7.4.3" +version = "3.10.0.0" description = "Backported and Experimental Type Hints for Python 3.5+" category = "main" optional = false @@ -1308,8 +1313,8 @@ atomicwrites = [ {file = "atomicwrites-1.4.0.tar.gz", hash = "sha256:ae70396ad1a434f9c7046fd2dd196fc04b12f9e91ffb859164193be8b6168a7a"}, ] attrs = [ - {file = "attrs-20.3.0-py2.py3-none-any.whl", hash = "sha256:31b2eced602aa8423c2aea9c76a724617ed67cf9513173fd3a4f03e3a929c7e6"}, - {file = "attrs-20.3.0.tar.gz", hash = "sha256:832aa3cde19744e49938b91fea06d69ecb9e649c93ba974535d08ad92164f700"}, + {file = "attrs-21.2.0-py2.py3-none-any.whl", hash = "sha256:149e90d6d8ac20db7a955ad60cf0e6881a3f20d37096140088356da6c716b0b1"}, + {file = "attrs-21.2.0.tar.gz", hash = "sha256:ef6aaac3ca6cd92904cdd0d83f629a15f18053ec84e6432106f7a4d04ae4f5fb"}, ] automat = [ {file = "Automat-20.2.0-py2.py3-none-any.whl", hash = "sha256:b6feb6455337df834f6c9962d6ccf771515b7d939bca142b29c20c2376bc6111"}, @@ -1457,8 +1462,8 @@ coverage = [ {file = "coverage-5.5.tar.gz", hash = "sha256:ebe78fe9a0e874362175b02371bdfbee64d8edc42a044253ddf4ee7d3c15212c"}, ] crochet = [ - {file = "crochet-1.12.0-py3-none-any.whl", hash = "sha256:9b54000f69c499083f3c39ee3e550122419e58e7090e6a3f5afa88604ede86e7"}, - {file = "crochet-1.12.0.tar.gz", hash = "sha256:8fcbc64768813f50ee76b17a1e8d32a9f39206f8ab6766d50c885e07e7fb6fb1"}, + {file = "crochet-2.0.0-py3-none-any.whl", hash = "sha256:de7306f0548581b5222c2d91f2175045e672591519896f717affb81ef66c0f5f"}, + {file = "crochet-2.0.0.tar.gz", hash = "sha256:5f7f6c0d41ec418da16080f0202faac6b30f84a6fca9d8911e9db541f8e4e521"}, ] cryptography = [ {file = "cryptography-2.9.2-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:daf54a4b07d67ad437ff239c8a4080cfd1cc7213df57d33c97de7b4738048d5e"}, @@ -1498,16 +1503,16 @@ faker = [ {file = "Faker-4.18.0.tar.gz", hash = "sha256:6279746aed175a693108238e6d1ab8d7e26d0ec7ff8474f61025b9fdaae15d65"}, ] fedora-messaging = [ - {file = "fedora_messaging-2.0.2-py2.py3-none-any.whl", hash = "sha256:50af6636220f563ac6a70a26cbcbb183cc1085085585a264bca69749f7cc7e72"}, - {file = "fedora_messaging-2.0.2.tar.gz", hash = "sha256:7222d4b45407da4e2dd0e2bfea21acc7cdc11335172e59a96fe5ccff108eab29"}, + {file = "fedora_messaging-2.1.0-py2.py3-none-any.whl", hash = "sha256:9292d64fbd4ec5b0233fcea6a098ae97a4d985000653b775ddb223ef571d9889"}, + {file = "fedora_messaging-2.1.0.tar.gz", hash = "sha256:3a66252f08720202fbd5cf69d1df611b3b7bb37a802094131d605facc6d05f32"}, ] flake8 = [ - {file = "flake8-3.9.1-py2.py3-none-any.whl", hash = "sha256:3b9f848952dddccf635be78098ca75010f073bfe14d2c6bda867154bea728d2a"}, - {file = "flake8-3.9.1.tar.gz", hash = "sha256:1aa8990be1e689d96c745c5682b687ea49f2e05a443aff1f8251092b0014e378"}, + {file = "flake8-3.9.2-py2.py3-none-any.whl", hash = "sha256:bf8fd333346d844f616e8d47905ef3a3384edae6b4e9beb0c5101e25e3110907"}, + {file = "flake8-3.9.2.tar.gz", hash = "sha256:07528381786f2a6237b061f6e96610a4167b226cb926e2aa2b6b1d78057c576b"}, ] flask = [ - {file = "Flask-1.1.2-py2.py3-none-any.whl", hash = "sha256:8a4fdd8936eba2512e9c85df320a37e694c93945b33ef33c89946a340a238557"}, - {file = "Flask-1.1.2.tar.gz", hash = "sha256:4efa1ae2d7c9865af48986de8aeb8504bf32c7f3d6fdc9353d34b21f4b127060"}, + {file = "Flask-1.1.4-py2.py3-none-any.whl", hash = "sha256:c34f04500f2cbbea882b1acb02002ad6fe6b7ffa64a6164577995657f50aed22"}, + {file = "Flask-1.1.4.tar.gz", hash = "sha256:0fbeb6180d383a9186d0d6ed954e0042ad9f18e0e8de088b2b419d526927d196"}, ] flask-babel = [ {file = "Flask-Babel-1.0.0.tar.gz", hash = "sha256:d6a70468f9a8919d59fba2a291a003da3a05ff884275dddbd965f3b98b09ab3e"}, @@ -1533,8 +1538,8 @@ gitdb = [ {file = "gitdb-4.0.7.tar.gz", hash = "sha256:96bf5c08b157a666fec41129e6d327235284cca4c81e92109260f353ba138005"}, ] gitpython = [ - {file = "GitPython-3.1.14-py3-none-any.whl", hash = "sha256:3283ae2fba31c913d857e12e5ba5f9a7772bbc064ae2bb09efafa71b0dd4939b"}, - {file = "GitPython-3.1.14.tar.gz", hash = "sha256:be27633e7509e58391f10207cd32b2a6cf5b908f92d9cd30da2e514e1137af61"}, + {file = "GitPython-3.1.17-py3-none-any.whl", hash = "sha256:29fe82050709760081f588dd50ce83504feddbebdc4da6956d02351552b1c135"}, + {file = "GitPython-3.1.17.tar.gz", hash = "sha256:ee24bdc93dce357630764db659edaf6b8d664d4ff5447ccfeedd2dc5c253f41e"}, ] gunicorn = [ {file = "gunicorn-20.1.0-py3-none-any.whl", hash = "sha256:9dcc4547dbb1cb284accfb15ab5667a0e5d1881cc443e0677b4882a4067a807e"}, @@ -1751,8 +1756,8 @@ pyflakes = [ {file = "pyflakes-2.3.1.tar.gz", hash = "sha256:f5bc8ecabc05bb9d291eb5203d6810b49040f6ff446a756326104746cc00c1db"}, ] pygments = [ - {file = "Pygments-2.8.1-py3-none-any.whl", hash = "sha256:534ef71d539ae97d4c3a4cf7d6f110f214b0e687e92f9cb9d2a3b0d3101289c8"}, - {file = "Pygments-2.8.1.tar.gz", hash = "sha256:2656e1a6edcdabf4275f9a3640db59fd5de107d88e8663c5d4e9a0fa62f77f94"}, + {file = "Pygments-2.9.0-py3-none-any.whl", hash = "sha256:d66e804411278594d764fc69ec36ec13d9ae9147193a1740cd34d272ca383b8e"}, + {file = "Pygments-2.9.0.tar.gz", hash = "sha256:a18f47b506a429f6f4b9df81bb02beab9ca21d0a5fee38ed15aef65f0545519f"}, ] pyjwt = [ {file = "PyJWT-1.7.1-py2.py3-none-any.whl", hash = "sha256:5c6eca3c2940464d106b99ba83b00c6add741c9becaec087fb7ccdefea71350e"}, @@ -1778,12 +1783,12 @@ pytest = [ {file = "pytest-5.4.3.tar.gz", hash = "sha256:7979331bfcba207414f5e1263b5a0f8f521d0f457318836a7355531ed1a4c7d8"}, ] pytest-cov = [ - {file = "pytest-cov-2.11.1.tar.gz", hash = "sha256:359952d9d39b9f822d9d29324483e7ba04a3a17dd7d05aa6beb7ea01e359e5f7"}, - {file = "pytest_cov-2.11.1-py2.py3-none-any.whl", hash = "sha256:bdb9fdb0b85a7cc825269a4c56b48ccaa5c7e365054b6038772c32ddcdc969da"}, + {file = "pytest-cov-2.12.0.tar.gz", hash = "sha256:8535764137fecce504a49c2b742288e3d34bc09eed298ad65963616cc98fd45e"}, + {file = "pytest_cov-2.12.0-py2.py3-none-any.whl", hash = "sha256:95d4933dcbbacfa377bb60b29801daa30d90c33981ab2a79e9ab4452c165066e"}, ] pytest-mock = [ - {file = "pytest-mock-3.6.0.tar.gz", hash = "sha256:f7c3d42d6287f4e45846c8231c31902b6fa2bea98735af413a43da4cf5b727f1"}, - {file = "pytest_mock-3.6.0-py3-none-any.whl", hash = "sha256:952139a535b5b48ac0bb2f90b5dd36b67c7e1ba92601f3a8012678c4bd7f0bcc"}, + {file = "pytest-mock-3.6.1.tar.gz", hash = "sha256:40217a058c52a63f1042f0784f62009e976ba824c418cced42e88d5f40ab0e62"}, + {file = "pytest_mock-3.6.1-py3-none-any.whl", hash = "sha256:30c2f2cc9759e76eee674b81ea28c9f0b94f8f0445a1b87762cadf774f0df7e3"}, ] pytest-vcr = [ {file = "pytest-vcr-1.0.2.tar.gz", hash = "sha256:23ee51b75abbcc43d926272773aae4f39f93aceb75ed56852d0bf618f92e1896"}, @@ -1887,12 +1892,12 @@ semantic-version = [ {file = "semantic_version-2.8.5.tar.gz", hash = "sha256:d2cb2de0558762934679b9a104e82eca7af448c9f4974d1f3eeccff651df8a54"}, ] service-identity = [ - {file = "service_identity-18.1.0-py2.py3-none-any.whl", hash = "sha256:001c0707759cb3de7e49c078a7c0c9cd12594161d3bf06b9c254fdcb1a60dc36"}, - {file = "service_identity-18.1.0.tar.gz", hash = "sha256:0858a54aabc5b459d1aafa8a518ed2081a285087f349fe3e55197989232e2e2d"}, + {file = "service-identity-21.1.0.tar.gz", hash = "sha256:6e6c6086ca271dc11b033d17c3a8bea9f24ebff920c587da090afc9519419d34"}, + {file = "service_identity-21.1.0-py2.py3-none-any.whl", hash = "sha256:f0b0caac3d40627c3c04d7a51b6e06721857a0e10a8775f2d1d7e72901b3a7db"}, ] six = [ - {file = "six-1.15.0-py2.py3-none-any.whl", hash = "sha256:8b74bedcbbbaca38ff6d7491d76f2b06b3592611af620f8426e82dddb04a5ced"}, - {file = "six-1.15.0.tar.gz", hash = "sha256:30639c035cdb23534cd4aa2dd52c3bf48f06e5f4a941509c8bafd8ce11080259"}, + {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, + {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, ] smmap = [ {file = "smmap-4.0.0-py2.py3-none-any.whl", hash = "sha256:a9a7479e4c572e2e775c404dcd3080c8dc49f39918c2cf74913d30c4c478e3c2"}, @@ -2004,9 +2009,9 @@ typed-ast = [ {file = "typed_ast-1.4.3.tar.gz", hash = "sha256:fb1bbeac803adea29cedd70781399c99138358c26d05fcbd23c13016b7f5ec65"}, ] typing-extensions = [ - {file = "typing_extensions-3.7.4.3-py2-none-any.whl", hash = "sha256:dafc7639cde7f1b6e1acc0f457842a83e722ccca8eef5270af2d74792619a89f"}, - {file = "typing_extensions-3.7.4.3-py3-none-any.whl", hash = "sha256:7cb407020f00f7bfc3cb3e7881628838e69d8f3fcab2f64742a5e76b2f841918"}, - {file = "typing_extensions-3.7.4.3.tar.gz", hash = "sha256:99d4073b617d30288f569d3f13d2bd7548c3a7e4c8de87db09a9d29bb3a4a60c"}, + {file = "typing_extensions-3.10.0.0-py2-none-any.whl", hash = "sha256:0ac0f89795dd19de6b97debb0c6af1c70987fd80a2d62d1958f7e56fcc31b497"}, + {file = "typing_extensions-3.10.0.0-py3-none-any.whl", hash = "sha256:779383f6086d90c99ae41cf0ff39aac8a7937a9283ce0a414e5dd782f4c94a84"}, + {file = "typing_extensions-3.10.0.0.tar.gz", hash = "sha256:50b6f157849174217d0656f99dc82fe932884fb250826c18350e159ec6cdf342"}, ] unidecode = [ {file = "Unidecode-1.2.0-py2.py3-none-any.whl", hash = "sha256:12435ef2fc4cdfd9cf1035a1db7e98b6b047fe591892e81f34e94959591fad00"}, diff --git a/pyproject.toml b/pyproject.toml index f07c7b085..ffff82b56 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "noggin-aaa" -version = "1.1.0" +version = "1.2.0" description = "Noggin is a self-service portal for FreeIPA. The primary purpose of the portal is to allow users to sign up and manage their account information and group membership." license = "MIT"