9 | {% blocktrans %}
10 | Forgot your password? Enter your email in the form below and we'll send you instructions for creating a new one.
11 | {% endblocktrans %}
12 |
13 |
14 |
21 |
22 | {% endblock %}
23 |
--------------------------------------------------------------------------------
/registration/__init__.py:
--------------------------------------------------------------------------------
1 | VERSION = (2, 13, 0, "final", 0)
2 |
3 | # for Django-3.1 and prior
4 | default_app_config = "registration.apps.RegistrationConfig"
5 |
6 |
7 | def get_version():
8 | "Returns a PEP 386-compliant version number from VERSION."
9 | assert len(VERSION) == 5
10 | assert VERSION[3] in ("alpha", "beta", "rc", "final")
11 |
12 | # Now build the two parts of the version number:
13 | # main = X.Y[.Z]
14 | # sub = .devN - for pre-alpha releases
15 | # | {a|b|c}N - for alpha, beta and rc releases
16 |
17 | parts = 2 if VERSION[2] == 0 else 3
18 | main = ".".join(str(x) for x in VERSION[:parts])
19 |
20 | sub = ""
21 | if VERSION[3] != "final":
22 | mapping = {"alpha": "a", "beta": "b", "rc": "c"}
23 | sub = mapping[VERSION[3]] + str(VERSION[4])
24 |
25 | return str(main + sub)
26 |
--------------------------------------------------------------------------------
/templates/registration/password_change_done.html:
--------------------------------------------------------------------------------
1 | {% extends "registration/registration_base.html" %}
2 | {% load i18n %}
3 |
4 | {% block title %}{% trans "Password Changed" %}{% endblock %}
5 |
6 | {% block content %}
7 |
8 |
9 |
{% trans "Password Changed" %}
10 |
11 | {% trans "Your password has been successfully changed!" %}
12 |
21 | {% endblock %}
22 |
23 | {# This is used by django.contrib.auth #}
24 |
--------------------------------------------------------------------------------
/templates/registration/password_reset_done.html:
--------------------------------------------------------------------------------
1 | {% extends "registration/registration_base.html" %}
2 | {% load i18n %}
3 |
4 | {% block title %}{% trans "Password Reset" %}{% endblock %}
5 |
6 | {% block content %}
7 |
8 |
9 |
{% trans "Password Reset" %}
10 |
11 | {% blocktrans %}
12 | We have sent you an email with a link to reset your password. Please check
13 | your email and click the link to continue.
14 | {% endblocktrans %}
15 |
"Please enter your sign up details below to access your
15 | account."
16 |
17 |
18 |
34 |
35 |
36 | {% endblock %}
37 |
38 |
39 | {% comment %}
40 | **registration/registration_form.html**
41 | Used to show the form users will fill out to register. By default, has
42 | the following context:
43 |
44 | ``form``
45 | The registration form. This will be an instance of some subclass
46 | of ``django.forms.Form``; consult `Django's forms documentation
47 | `_ for
48 | information on how to display this in a template.
49 | {% endcomment %}
50 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug_report.yml:
--------------------------------------------------------------------------------
1 | name: 🐛 Bug
2 | description: Report an issue to help improve the project.
3 | title: '[BUG] '
4 | labels: ['bug', 'status: awaiting triage']
5 | body:
6 | - type: checkboxes
7 | id: duplicates
8 | attributes:
9 | label: Has this bug been raised before?
10 | description: Increase the chances of your issue being accepted by making sure it has not been raised before.
11 | options:
12 | - label: I have checked "open" AND "closed" issues and this is not a duplicate
13 | required: true
14 | - type: textarea
15 | id: description
16 | attributes:
17 | label: Description
18 | description: A clear description of the bug you have found. Please include relevant information and resources (for example the steps to reproduce the bug)
19 | validations:
20 | required: true
21 | - type: textarea
22 | id: steps
23 | attributes:
24 | label: Steps to Reproduce
25 | description: To help us recreate the bug, provide a numbered list of the exact steps taken to trigger the buggy behavior.
26 | value: |
27 | Include any relevant details like:
28 |
29 | - What page you were on...
30 | - What you were trying to do...
31 | - What went wrong...
32 | validations:
33 | required: true
34 | - type: textarea
35 | id: screenshots
36 | attributes:
37 | label: Screenshots
38 | description: Please add screenshots if applicable
39 | validations:
40 | required: false
41 | - type: dropdown
42 | id: assignee
43 | attributes:
44 | label: Do you want to work on this issue?
45 | multiple: false
46 | options:
47 | - 'No'
48 | - 'Yes'
49 | default: 0
50 | validations:
51 | required: false
52 | - type: textarea
53 | id: extrainfo
54 | attributes:
55 | label: If "yes" to above, please explain how you would technically implement this
56 | description: For example reference any existing code
57 | validations:
58 | required: false
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request.yml:
--------------------------------------------------------------------------------
1 | name: 💡 General Feature Request
2 | description: Have a new idea/feature? Let us know...
3 | title: '[FEATURE] '
4 | labels: ['enhancement', 'feature', 'status: awaiting triage']
5 | body:
6 | - type: checkboxes
7 | id: duplicates
8 | attributes:
9 | label: Is this a unique feature?
10 | description: Increase the chances of your issue being accepted by making sure it has not been raised before.
11 | options:
12 | - label: I have checked "open" AND "closed" issues and this is not a duplicate
13 | required: true
14 | - type: textarea
15 | attributes:
16 | label: Is your feature request related to a problem/unavailable functionality? Please describe.
17 | description: A clear and concise description of what the problem is (for example "I'm always frustrated when [...]").
18 | validations:
19 | required: true
20 | - type: textarea
21 | id: description
22 | attributes:
23 | label: Proposed Solution
24 | description: A clear description of the enhancement you propose. Please include relevant information and resources (for example another project's implementation of this feature).
25 | validations:
26 | required: true
27 | - type: textarea
28 | id: screenshots
29 | attributes:
30 | label: Screenshots
31 | description: Please add screenshots of the before and/or after the proposed changes.
32 | validations:
33 | required: false
34 | - type: dropdown
35 | id: assignee
36 | attributes:
37 | label: Do you want to work on this issue?
38 | multiple: false
39 | options:
40 | - 'No'
41 | - 'Yes'
42 | default: 0
43 | validations:
44 | required: false
45 | - type: textarea
46 | id: extrainfo
47 | attributes:
48 | label: If "yes" to above, please explain how you would technically implement this (issue will not be assigned if this is skipped)
49 | description: For example reference any existing code or library
50 | validations:
51 | required: false
--------------------------------------------------------------------------------
/templates/base.html:
--------------------------------------------------------------------------------
1 |
2 | {% load static %}
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 | {% block title %}{% endblock %}
21 |
22 |
23 |
25 |
26 |
27 |
31 |
32 |
36 |
37 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 | {% block content %}
52 | {% endblock %}
53 |
54 |
55 |
--------------------------------------------------------------------------------
/registration/forms.py:
--------------------------------------------------------------------------------
1 | """
2 | Forms and validation code for user registration.
3 |
4 | Note that all of these forms assume Django's bundle default ``User``
5 | model; since it's not possible for a form to anticipate in advance the
6 | needs of custom user models, you will need to write your own forms if
7 | you're using a custom model.
8 |
9 | """
10 |
11 | from django import forms
12 | from django.contrib.auth.forms import BaseUserCreationForm
13 |
14 | from .users import UserModel
15 | from .users import UsernameField
16 | from .utils import _
17 | from .models import Profile
18 | from crispy_forms.helper import FormHelper
19 | from crispy_forms.layout import Layout, Submit
20 |
21 |
22 | User = UserModel()
23 |
24 |
25 | class RegistrationForm(BaseUserCreationForm):
26 | """
27 | Form for registering a new user account.
28 |
29 | Validates that the requested username is not already in use, and
30 | requires the password to be entered twice to catch typos.
31 |
32 | Subclasses should feel free to add any additional validation they
33 | need, but should avoid defining a ``save()`` method -- the actual
34 | saving of collected user data is delegated to the active
35 | registration backend.
36 |
37 | """
38 |
39 | required_css_class = "required "
40 | email = forms.EmailField(label=_("E-mail"))
41 |
42 | class Meta:
43 | model = User
44 | fields = (UsernameField(), "email")
45 |
46 |
47 | class ResendActivationForm(forms.Form):
48 | required_css_class = "required"
49 | email = forms.EmailField(label=_("E-mail"))
50 |
51 |
52 | class UpdateForm(forms.ModelForm):
53 |
54 | class Meta:
55 | model = Profile
56 | fields = (
57 | "name",
58 | "surname",
59 | "profile_image",
60 | "profession",
61 | "organization",
62 | "website",
63 | )
64 |
65 | def __init__(self, *args, **kwargs):
66 | super(UpdateForm, self).__init__(*args, **kwargs)
67 |
68 | self.helper = FormHelper()
69 | self.helper.form_id = "id-Crispy_UpdateForm"
70 | self.helper.form_class = "form-horizontal"
71 | self.helper.add_input(Submit("update", "Update Profile"))
72 |
--------------------------------------------------------------------------------
/templates/registration/activation_email.html:
--------------------------------------------------------------------------------
1 | {% load i18n %}
2 |
3 |
4 |
5 |
6 | {{ site.name }} {% trans "registration" %}
7 |
8 |
9 |
10 |
11 | {% blocktrans with site_name=site.name %}
12 | You (or someone pretending to be you) have asked to register an account at
13 | {{ site_name }}. If this wasn't you, please ignore this email
14 | and your address will be removed from our records.
15 | {% endblocktrans %}
16 |
17 |
18 | {% blocktrans %}
19 | To activate this account, please click the following link within the next
20 | {{ expiration_days }} days:
21 | {% endblocktrans %}
22 |
35 |
36 |
37 |
38 |
39 |
40 | {% comment %}
41 | **registration/activation_email.html**
42 |
43 | Used to generate the html body of the activation email. Should display a
44 | link the user can click to activate the account. This template has the
45 | following context:
46 |
47 | ``activation_key``
48 | The activation key for the new account.
49 |
50 | ``expiration_days``
51 | The number of days remaining during which the account may be
52 | activated.
53 |
54 | ``site``
55 | An object representing the site on which the user registered;
56 | depending on whether ``django.contrib.sites`` is installed, this
57 | may be an instance of either ``django.contrib.sites.models.Site``
58 | (if the sites application is installed) or
59 | ``django.contrib.sites.requests.RequestSite`` (if not). Consult `the
60 | documentation for the Django sites framework
61 | `_ for
62 | details regarding these objects' interfaces.
63 |
64 | ``user``
65 | The new user account
66 |
67 | ``request``
68 | ``HttpRequest`` instance for better flexibility.
69 | For example it can be used to compute absolute register URL:
70 |
71 | {{ request.scheme }}://{{ request.get_host }}{% url 'registration_activate' activation_key %}
72 | {% endcomment %}
73 |
--------------------------------------------------------------------------------
/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | # **VetDataHub Code of Conduct**
2 |
3 | ## **Introduction**
4 | At VetDataHub, we are committed to creating a safe, inclusive, and respectful environment for all contributors, users, and members of our community. This Code of Conduct outlines our expectations for behavior and provides guidance for reporting unacceptable behavior.
5 |
6 | ## **Scope**
7 | This Code of Conduct applies to all community spaces, including the VetDataHub platform, forums, GitHub repositories, Discord server, social media, and any in-person or virtual events organized by VetDataHub.
8 |
9 | ---
10 |
11 | ## **Our Standards**
12 |
13 | ### **Expected Behavior**
14 | - Be respectful and considerate in speech and actions.
15 | - Actively promote inclusivity and diversity.
16 | - Provide constructive feedback and engage in healthy discussions.
17 | - Respect differing opinions, viewpoints, and experiences.
18 | - Comply with all applicable laws and regulations.
19 |
20 | ### **Unacceptable Behavior**
21 | - Harassment, bullying, or discrimination of any kind, including on the basis of gender, sexual orientation, disability, ethnicity, religion, or age.
22 | - The use of inappropriate, abusive, or threatening language or imagery.
23 | - Posting or sharing illegal or inappropriate content, including data that violates privacy or ethical guidelines.
24 | - Disruptive behavior, such as trolling or spamming.
25 | - Unauthorized access to or misuse of the VetDataHub platform or resources.
26 |
27 | ---
28 |
29 | ## **Reporting Issues**
30 | If you witness or experience any unacceptable behavior, please report it to the VetDataHub team by emailing **[vetdatahub@gmail.com]**. All reports will be treated with confidentiality and addressed promptly.
31 |
32 | ---
33 |
34 | ## **Enforcement**
35 | VetDataHub moderators and administrators are responsible for enforcing this Code of Conduct. They have the authority to:
36 | - Remove comments, data, or other contributions that violate the Code of Conduct.
37 | - Restrict access to or remove individuals from community spaces for severe or repeated violations.
38 | - Take additional actions as necessary to maintain a safe and respectful environment.
39 |
40 | ---
41 |
42 | ## **Acknowledgment**
43 | This Code of Conduct is inspired by the **Contributor Covenant** and adapted to fit the needs of the VetDataHub community.
44 |
45 | ---
46 |
47 | ## **Contact Us**
48 | If you have any questions or concerns about this Code of Conduct, please reach out to the VetDataHub team at **[vetdatahub@gmail.com]**.
49 |
--------------------------------------------------------------------------------
/registration/backends/default/urls.py:
--------------------------------------------------------------------------------
1 | """
2 | URLconf for registration and activation, using django-registration's
3 | default backend.
4 |
5 | If the default behavior of these views is acceptable to you, simply
6 | use a line like this in your root URLconf to set up the default URLs
7 | for registration::
8 |
9 | (r'^accounts/', include('registration.backends.default.urls')),
10 |
11 | This will also automatically set up the views in
12 | ``django.contrib.auth`` at sensible default locations.
13 |
14 | If you'd like to customize registration behavior, feel free to set up
15 | your own URL patterns for these views instead.
16 |
17 | """
18 |
19 | from django.conf import settings
20 | from django.conf.urls import include
21 | from django.urls import path
22 | from django.views.generic.base import TemplateView
23 |
24 | from .views import ActivationView
25 | from .views import RegistrationView
26 | from .views import ResendActivationView
27 |
28 | urlpatterns = [
29 | path(
30 | "activate/complete/",
31 | TemplateView.as_view(
32 | template_name="registration/activation_complete.html"
33 | ),
34 | name="registration_activation_complete",
35 | ),
36 | path(
37 | "activate/resend/",
38 | ResendActivationView.as_view(),
39 | name="registration_resend_activation",
40 | ),
41 | # Activation keys get matched by \w+ instead of the more specific
42 | # [a-fA-F0-9]{40} because a bad activation key should still get to the view;
43 | # that way it can return a sensible "invalid key" message instead of a
44 | # confusing 404.
45 | path(
46 | "activate//",
47 | ActivationView.as_view(),
48 | name="registration_activate",
49 | ),
50 | path(
51 | "register/complete/",
52 | TemplateView.as_view(
53 | template_name="registration/registration_complete.html"
54 | ),
55 | name="registration_complete",
56 | ),
57 | path(
58 | "register/closed/",
59 | TemplateView.as_view(
60 | template_name="registration/registration_closed.html"
61 | ),
62 | name="registration_disallowed",
63 | ),
64 | ]
65 |
66 | if getattr(settings, "INCLUDE_REGISTER_URL", True):
67 | urlpatterns += [
68 | path(
69 | "register/",
70 | RegistrationView.as_view(),
71 | name="registration_register",
72 | ),
73 | ]
74 |
75 | if getattr(settings, "INCLUDE_AUTH_URLS", True):
76 | urlpatterns += [
77 | path("", include("registration.auth_urls")),
78 | ]
79 |
--------------------------------------------------------------------------------
/registration/auth_urls.py:
--------------------------------------------------------------------------------
1 | """
2 | URL patterns for the views included in ``django.contrib.auth``.
3 |
4 | Including these URLs (via the ``include()`` directive) will set up the
5 | following patterns based at whatever URL prefix they are included
6 | under:
7 |
8 | * User login at ``login/``.
9 |
10 | * User logout at ``logout/``.
11 |
12 | * The two-step password change at ``password/change/`` and
13 | ``password/change/done/``.
14 |
15 | * The four-step password reset at ``password/reset/``,
16 | ``password/reset/confirm/``, ``password/reset/complete/`` and
17 | ``password/reset/done/``.
18 |
19 | The default registration backend already has an ``include()`` for
20 | these URLs, so under the default setup it is not necessary to manually
21 | include these views. Other backends may or may not include them;
22 | consult a specific backend's documentation for details.
23 |
24 | """
25 |
26 | from django.contrib.auth import views as auth_views
27 | from django.urls import path
28 | from django.urls import reverse_lazy
29 |
30 | urlpatterns = [
31 | path(
32 | "login/",
33 | auth_views.LoginView.as_view(template_name="registration/login.html"),
34 | name="auth_login",
35 | ),
36 | path(
37 | "logout/",
38 | auth_views.LogoutView.as_view(template_name="registration/logout.html"),
39 | name="auth_logout",
40 | ),
41 | path(
42 | "password/change/",
43 | auth_views.PasswordChangeView.as_view(
44 | success_url=reverse_lazy("auth_password_change_done")
45 | ),
46 | name="auth_password_change",
47 | ),
48 | path(
49 | "password/change/done/",
50 | auth_views.PasswordChangeDoneView.as_view(),
51 | name="auth_password_change_done",
52 | ),
53 | path(
54 | "password/reset/",
55 | auth_views.PasswordResetView.as_view(
56 | success_url=reverse_lazy("auth_password_reset_done")
57 | ),
58 | name="auth_password_reset",
59 | ),
60 | path(
61 | "password/reset/complete/",
62 | auth_views.PasswordResetCompleteView.as_view(),
63 | name="auth_password_reset_complete",
64 | ),
65 | path(
66 | "password/reset/done/",
67 | auth_views.PasswordResetDoneView.as_view(),
68 | name="auth_password_reset_done",
69 | ),
70 | path(
71 | "password/reset/confirm///",
72 | auth_views.PasswordResetConfirmView.as_view(
73 | success_url=reverse_lazy("auth_password_reset_complete")
74 | ),
75 | name="auth_password_reset_confirm",
76 | ),
77 | ]
78 |
--------------------------------------------------------------------------------
/templates/datasets/dataset_list.html:
--------------------------------------------------------------------------------
1 | {% extends 'dashboard.html' %}
2 | {% block title %}List Datasets{% endblock %}
3 | {% block main %}
4 |
5 |
Datasets
6 |
7 | Browse our collection of datasets for your next project.
8 |
9 |
10 |
11 |
12 | {% if datasets %}
13 |
14 | {% for dataset in datasets%}
15 |
16 |
19 |
20 |
21 | {{dataset.name}}
22 |
23 |
24 | {{dataset.description}}
25 |
26 |
27 |
28 |
29 |
32 |
46 |
47 | Category
48 | {% for tag in dataset.tags.all %}
49 |
103 | Our website is currently undergoing updates; you may notice periodic
104 | changes. We appreciate your patience and understanding during this
105 | time.
106 |
VetDataHub is an open-source platform for sharing veterinary datasets to advance medical research.
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
Explore Our Features
19 |
Key features of this project include secure user login and authentication, dataset management, and a user-friendly interface.
20 |
21 |
22 |
23 |
24 |
View Datasets
25 |
26 |
27 |
28 |
Upload Datasets
29 |
30 |
31 |
32 |
Download Datasets
33 |
34 |
35 |
36 |
Explore Datasets
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
Diverse Datasets
46 |
47 | Explore a wide range of veterinary datasets, including medical images, clinical records, genomic data, epidemiological data, and more.
48 |
49 |
50 |
51 |
52 |
53 |
54 |
Community Collaboration
55 |
56 | Engage with a vibrant community of contributors and users passionate about leveraging data science for animal welfare.
57 |
58 |
59 |
60 |
61 |
62 |
63 |
Open Access
64 |
65 | Access datasets freely, empowering researchers, students, and practitioners to address pressing challenges in veterinary medicine.
66 |
67 |
68 |
69 |
70 |
71 |
72 |
Ethical Standards
73 |
74 | Uphold ethical standards and data privacy principles to ensure responsible data sharing and usage.
75 |
76 |
77 |
78 |
79 |
80 |
81 |
Documentation and Support
82 |
83 | Benefit from comprehensive documentation, tutorials, and user support to facilitate dataset discovery, understanding, and utilization.
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
About Us
92 |
93 |
94 |
95 |
100 |
101 |
102 |
103 |
104 | The project aims to make open-source veterinary data available to veterinary professionals, researchers, and data scientists from around the world to contribute, discover, and utilize valuable datasets for research, diagnosis, and decision-making in animal health.
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
Get in touch
114 |
We'd love to hear from you. Our friendly team is always here to chat.
115 |
116 |
Email: vetdatahub@gmail.com
117 |
118 |
119 |
120 |
Send us a message
121 |
127 |
128 |
129 |
130 | {% endblock %}
131 | {% include "footer.html" %}
132 |
--------------------------------------------------------------------------------
/Pipfile.lock:
--------------------------------------------------------------------------------
1 | {
2 | "_meta": {
3 | "hash": {
4 | "sha256": "3a3d6607976b6ff2ea64422abc0483df81aa287e60ad0e53bf363da69eaa36ec"
5 | },
6 | "pipfile-spec": 6,
7 | "requires": {
8 | "python_version": "3.12"
9 | },
10 | "sources": [
11 | {
12 | "name": "pypi",
13 | "url": "https://pypi.org/simple",
14 | "verify_ssl": true
15 | }
16 | ]
17 | },
18 | "default": {
19 | "asgiref": {
20 | "hashes": [
21 | "sha256:3e1e3ecc849832fe52ccf2cb6686b7a55f82bb1d6aee72a58826471390335e47",
22 | "sha256:c343bd80a0bec947a9860adb4c432ffa7db769836c64238fc34bdc3fec84d590"
23 | ],
24 | "markers": "python_version >= '3.8'",
25 | "version": "==3.8.1"
26 | },
27 | "black": {
28 | "hashes": [
29 | "sha256:14b3502784f09ce2443830e3133dacf2c0110d45191ed470ecb04d0f5f6fcb0f",
30 | "sha256:17374989640fbca88b6a448129cd1745c5eb8d9547b464f281b251dd00155ccd",
31 | "sha256:1c536fcf674217e87b8cc3657b81809d3c085d7bf3ef262ead700da345bfa6ea",
32 | "sha256:1cbacacb19e922a1d75ef2b6ccaefcd6e93a2c05ede32f06a21386a04cedb981",
33 | "sha256:1f93102e0c5bb3907451063e08b9876dbeac810e7da5a8bfb7aeb5a9ef89066b",
34 | "sha256:2cd9c95431d94adc56600710f8813ee27eea544dd118d45896bb734e9d7a0dc7",
35 | "sha256:30d2c30dc5139211dda799758559d1b049f7f14c580c409d6ad925b74a4208a8",
36 | "sha256:394d4ddc64782e51153eadcaaca95144ac4c35e27ef9b0a42e121ae7e57a9175",
37 | "sha256:3bb2b7a1f7b685f85b11fed1ef10f8a9148bceb49853e47a294a3dd963c1dd7d",
38 | "sha256:4007b1393d902b48b36958a216c20c4482f601569d19ed1df294a496eb366392",
39 | "sha256:5a2221696a8224e335c28816a9d331a6c2ae15a2ee34ec857dcf3e45dbfa99ad",
40 | "sha256:63f626344343083322233f175aaf372d326de8436f5928c042639a4afbbf1d3f",
41 | "sha256:649fff99a20bd06c6f727d2a27f401331dc0cc861fb69cde910fe95b01b5928f",
42 | "sha256:680359d932801c76d2e9c9068d05c6b107f2584b2a5b88831c83962eb9984c1b",
43 | "sha256:846ea64c97afe3bc677b761787993be4991810ecc7a4a937816dd6bddedc4875",
44 | "sha256:b5e39e0fae001df40f95bd8cc36b9165c5e2ea88900167bddf258bacef9bbdc3",
45 | "sha256:ccfa1d0cb6200857f1923b602f978386a3a2758a65b52e0950299ea014be6800",
46 | "sha256:d37d422772111794b26757c5b55a3eade028aa3fde43121ab7b673d050949d65",
47 | "sha256:ddacb691cdcdf77b96f549cf9591701d8db36b2f19519373d60d31746068dbf2",
48 | "sha256:e6668650ea4b685440857138e5fe40cde4d652633b1bdffc62933d0db4ed9812",
49 | "sha256:f9da3333530dbcecc1be13e69c250ed8dfa67f43c4005fb537bb426e19200d50",
50 | "sha256:fe4d6476887de70546212c99ac9bd803d90b42fc4767f058a0baa895013fbb3e"
51 | ],
52 | "index": "pypi",
53 | "markers": "python_version >= '3.9'",
54 | "version": "==24.10.0"
55 | },
56 | "click": {
57 | "hashes": [
58 | "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28",
59 | "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de"
60 | ],
61 | "markers": "python_version >= '3.7'",
62 | "version": "==8.1.7"
63 | },
64 | "django": {
65 | "hashes": [
66 | "sha256:021ffb7fdab3d2d388bc8c7c2434eb9c1f6f4d09e6119010bbb1694dda286bc2",
67 | "sha256:71603f27dac22a6533fb38d83072eea9ddb4017fead6f67f2562a40402d61c3f"
68 | ],
69 | "index": "pypi",
70 | "markers": "python_version >= '3.10'",
71 | "version": "==5.1.1"
72 | },
73 | "flake8": {
74 | "hashes": [
75 | "sha256:049d058491e228e03e67b390f311bbf88fce2dbaa8fa673e7aea87b7198b8d38",
76 | "sha256:597477df7860daa5aa0fdd84bf5208a043ab96b8e96ab708770ae0364dd03213"
77 | ],
78 | "index": "pypi",
79 | "markers": "python_full_version >= '3.8.1'",
80 | "version": "==7.1.1"
81 | },
82 | "mccabe": {
83 | "hashes": [
84 | "sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325",
85 | "sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e"
86 | ],
87 | "markers": "python_version >= '3.6'",
88 | "version": "==0.7.0"
89 | },
90 | "mypy-extensions": {
91 | "hashes": [
92 | "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d",
93 | "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"
94 | ],
95 | "markers": "python_version >= '3.5'",
96 | "version": "==1.0.0"
97 | },
98 | "packaging": {
99 | "hashes": [
100 | "sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002",
101 | "sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124"
102 | ],
103 | "markers": "python_version >= '3.8'",
104 | "version": "==24.1"
105 | },
106 | "pathspec": {
107 | "hashes": [
108 | "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08",
109 | "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712"
110 | ],
111 | "markers": "python_version >= '3.8'",
112 | "version": "==0.12.1"
113 | },
114 | "platformdirs": {
115 | "hashes": [
116 | "sha256:357fb2acbc885b0419afd3ce3ed34564c13c9b95c89360cd9563f73aa5e2b907",
117 | "sha256:73e575e1408ab8103900836b97580d5307456908a03e92031bab39e4554cc3fb"
118 | ],
119 | "markers": "python_version >= '3.8'",
120 | "version": "==4.3.6"
121 | },
122 | "pycodestyle": {
123 | "hashes": [
124 | "sha256:46f0fb92069a7c28ab7bb558f05bfc0110dac69a0cd23c61ea0040283a9d78b3",
125 | "sha256:6838eae08bbce4f6accd5d5572075c63626a15ee3e6f842df996bf62f6d73521"
126 | ],
127 | "markers": "python_version >= '3.8'",
128 | "version": "==2.12.1"
129 | },
130 | "pyflakes": {
131 | "hashes": [
132 | "sha256:1c61603ff154621fb2a9172037d84dca3500def8c8b630657d1701f026f8af3f",
133 | "sha256:84b5be138a2dfbb40689ca07e2152deb896a65c3a3e24c251c5c62489568074a"
134 | ],
135 | "markers": "python_version >= '3.8'",
136 | "version": "==3.2.0"
137 | },
138 | "sqlparse": {
139 | "hashes": [
140 | "sha256:773dcbf9a5ab44a090f3441e2180efe2560220203dc2f8c0b0fa141e18b505e4",
141 | "sha256:bb6b4df465655ef332548e24f08e205afc81b9ab86cb1c45657a7ff173a3a00e"
142 | ],
143 | "markers": "python_version >= '3.8'",
144 | "version": "==0.5.1"
145 | }
146 | },
147 | "develop": {}
148 | }
149 |
--------------------------------------------------------------------------------
/registration/backends/default/views.py:
--------------------------------------------------------------------------------
1 | from django.conf import settings
2 | from django.contrib.sites.shortcuts import get_current_site
3 | from django.shortcuts import render
4 |
5 | from ... import signals
6 | from ...models import RegistrationProfile
7 | from ...users import UserModel
8 | from ...views import ActivationView as BaseActivationView
9 | from ...views import RegistrationView as BaseRegistrationView
10 | from ...views import ResendActivationView as BaseResendActivationView
11 |
12 |
13 | class RegistrationView(BaseRegistrationView):
14 | """
15 | A registration backend which follows a simple workflow:
16 |
17 | 1. User signs up, inactive account is created.
18 |
19 | 2. Email is sent to user with activation link.
20 |
21 | 3. User clicks activation link, account is now active.
22 |
23 | Using this backend requires that
24 |
25 | * ``registration`` be listed in the ``INSTALLED_APPS`` setting
26 | (since this backend makes use of models defined in this
27 | application).
28 |
29 | * The setting ``ACCOUNT_ACTIVATION_DAYS`` be supplied, specifying
30 | (as an integer) the number of days from registration during
31 | which a user may activate their account (after that period
32 | expires, activation will be disallowed).
33 |
34 | * The creation of the templates
35 | ``registration/activation_email_subject.txt`` and
36 | ``registration/activation_email.txt``, which will be used for
37 | the activation email. See the notes for this backends
38 | ``register`` method for details regarding these templates.
39 |
40 | When subclassing this view, you can set the ``SEND_ACTIVATION_EMAIL``
41 | class variable to False to skip sending the new user a confirmation
42 | email or set ``SEND_ACTIVATION_EMAIL`` to ``False``. Doing so implies
43 | that you will have to activate the user manually from the admin site or
44 | send an activation by some other method. For example, by listening for
45 | the ``user_registered`` signal.
46 |
47 | Additionally, registration can be temporarily closed by adding the
48 | setting ``REGISTRATION_OPEN`` and setting it to
49 | ``False``. Omitting this setting, or setting it to ``True``, will
50 | be interpreted as meaning that registration is currently open and
51 | permitted.
52 |
53 | Internally, this is accomplished via storing an activation key in
54 | an instance of ``registration.models.RegistrationProfile``. See
55 | that model and its custom manager for full documentation of its
56 | fields and supported operations.
57 |
58 | """
59 |
60 | SEND_ACTIVATION_EMAIL = getattr(settings, "SEND_ACTIVATION_EMAIL", True)
61 | success_url = "registration_complete"
62 |
63 | registration_profile = RegistrationProfile
64 |
65 | def register(self, form):
66 | """
67 | Given a username, email address and password, register a new
68 | user account, which will initially be inactive.
69 |
70 | Along with the new ``User`` object, a new
71 | ``registration.models.RegistrationProfile`` will be created,
72 | tied to that ``User``, containing the activation key which
73 | will be used for this account.
74 |
75 | An email will be sent to the supplied email address; this
76 | email should contain an activation link. The email will be
77 | rendered using two templates. See the documentation for
78 | ``RegistrationProfile.send_activation_email()`` for
79 | information about these templates and the contexts provided to
80 | them.
81 |
82 | After the ``User`` and ``RegistrationProfile`` are created and
83 | the activation email is sent, the signal
84 | ``registration.signals.user_registered`` will be sent, with
85 | the new ``User`` as the keyword argument ``user`` and the
86 | class of this backend as the sender.
87 |
88 | """
89 | site = get_current_site(self.request)
90 |
91 | if hasattr(form, "save"):
92 | new_user_instance = form.save(commit=False)
93 | else:
94 | new_user_instance = UserModel().objects.create_user(
95 | **form.cleaned_data
96 | )
97 |
98 | new_user = self.registration_profile.objects.create_inactive_user(
99 | new_user=new_user_instance,
100 | site=site,
101 | send_email=self.SEND_ACTIVATION_EMAIL,
102 | request=self.request,
103 | )
104 | signals.user_registered.send(
105 | sender=self.__class__, user=new_user, request=self.request
106 | )
107 | return new_user
108 |
109 | def registration_allowed(self):
110 | """
111 | Indicate whether account registration is currently permitted,
112 | based on the value of the setting ``REGISTRATION_OPEN``. This
113 | is determined as follows:
114 |
115 | * If ``REGISTRATION_OPEN`` is not specified in settings, or is
116 | set to ``True``, registration is permitted.
117 |
118 | * If ``REGISTRATION_OPEN`` is both specified and set to
119 | ``False``, registration is not permitted.
120 |
121 | """
122 | return getattr(settings, "REGISTRATION_OPEN", True)
123 |
124 |
125 | class ActivationView(BaseActivationView):
126 |
127 | registration_profile = RegistrationProfile
128 |
129 | def activate(self, *args, **kwargs):
130 | """
131 | Given an an activation key, look up and activate the user
132 | account corresponding to that key (if possible).
133 |
134 | After successful activation, the signal
135 | ``registration.signals.user_activated`` will be sent, with the
136 | newly activated ``User`` as the keyword argument ``user`` and
137 | the class of this backend as the sender.
138 |
139 | """
140 | activation_key = kwargs.get("activation_key", "")
141 | site = get_current_site(self.request)
142 | user, activated = self.registration_profile.objects.activate_user(
143 | activation_key, site
144 | )
145 | if activated:
146 | signals.user_activated.send(
147 | sender=self.__class__, user=user, request=self.request
148 | )
149 | return user
150 |
151 | def get_success_url(self, user):
152 | return ("registration_activation_complete", (), {})
153 |
154 |
155 | class ResendActivationView(BaseResendActivationView):
156 |
157 | registration_profile = RegistrationProfile
158 |
159 | def resend_activation(self, form):
160 | """
161 | Given an email, look up user by email and resend activation key
162 | if user is not already activated or previous activation key has
163 | not expired. Note that if multiple users exist with the given
164 | email, no emails will be sent.
165 |
166 | Returns True if activation key was successfully sent, False otherwise.
167 |
168 | """
169 | site = get_current_site(self.request)
170 | email = form.cleaned_data["email"]
171 | return self.registration_profile.objects.resend_activation_mail(
172 | email, site, self.request
173 | )
174 |
175 | def render_form_submitted_template(self, form):
176 | """
177 | Renders resend activation complete template with the submitted email.
178 |
179 | """
180 | email = form.cleaned_data["email"]
181 | context = {"email": email}
182 | return render(
183 | self.request,
184 | "registration/resend_activation_complete.html",
185 | context,
186 | )
187 |
--------------------------------------------------------------------------------
Comments
80 | {% if comment_results %} 81 |82 | {% for comment in comment_results %} 83 |-
84 |
91 | {% endfor %}
92 |
93 | {% else %} 94 |{{ comment.content|truncatewords:20 }}
85 | From discussion: 86 | 87 | {{ comment.discussion.title }} 88 | 89 | 90 |No comments found.
95 | {% endif %} 96 |