cyface / django-termsandconditions Goto Github PK
View Code? Open in Web Editor NEWDjango Terms and Conditions Module
License: BSD 3-Clause "New" or "Revised" License
Django Terms and Conditions Module
License: BSD 3-Clause "New" or "Revised" License
Some templates have inline javascript which is bad for content security policy.
I cannot find any other ones. Also check if there is inline css anywhere. There should not be any inline css/javascript code.
You can use django-csp to test.
On a side note, I also see some jquery links in the demo templates. Why not use vanilla javascript instead of jquery? Bootstrap v5 is moving away from jquery for speed and other reasons like not relying on another library.
Up until now I've wrapped terms_required to add this check.
@cyface I can submit PR if you'd approve this feature? Or can it already be accomplished?
Hi,
While upgrading to the newer termsandconditions with an app I'm using (seahub), I encountered a failure. The following patches fixes things for me.
--- django-termsandconditions.orig/termsandconditions/models.py
+++ django-termsandconditions/termsandconditions/models.py
@@ -124,7 +124,7 @@ class TermsAndConditions(models.Model):
cache.set('tandc.not_agreed_terms_' + user.get_username(), not_agreed_terms, TERMS_CACHE_SECONDS)
except (TypeError, UserTermsAndConditions.DoesNotExist):
- return None
+ return []
return not_agreed_terms
Hi there!
I found your module quite interesting and relevant for our needs. However, for our use case, I would propose a couple of updates/changes:
If you accept the proposal, I could work towards a respective pull request. Alternatively, if you don't approve, I'm okey with introducing these changes in a separate repo. Let me know.
In any case, thanks a lot for your work and efforts! ;)
Regards,
Adrian
Is there a template tag to determine if the user accepted or declined the terms and conditions? I want to do something like:
If user accepts:
<a href="/terms/active/">
Else:
<a href="/terms/">
Print Link With Template Tags:
<a href="/terms/print/{{slug}}/{{version}}/">
I am not sure what the condition of the if statement template tag would be to determine if the user accepted/declined the terms or not. Or if there is a template tag to determine active or not?
Also, what order / hierarchy would you recommend for an if statement like this?
Feel free to close this issue and reply with a comment I will search for it later on.
This is a feature request. Be able to ask the user for their terms and conditions consent on the signup page via a checkbox that should submit to the terms and conditions database logs but then do not run the middleware after a successful signup for the first time. Then for new updates to the terms, the middleware could run normally.
Maybe have a setting like TERMS_MIDDLEWARE_ACTIVE_ON_SIGNUP = True|False would do the trick.
It occurred to me that doing something like asking for the user's PII like their email address on the signup page might be a violation of laws without their consent directly on that signup page. Since the current behavior with the middleware only allows a user to consent to the terms right after signing up and not during the signup page itself when it is already to late to consent about their PII being collected.
Here is my code below. Wondering how to get the checkbox to be able to log to the terms and conditions models instead of my own model especially without the user being created yet. I am using django-allauth's signup form. Or maybe I should just keep their response to the terms checkbox in my own model and not in the terms and conditions model?
Forms.py:
class CustomCheckbox(Field):
template = 'custom_checkbox.html'
class SignupForm(SignupForm):
terms_consent = forms.BooleanField(required=True,initial=False,label='I consent to the terms and conditions?')
field_order = ['username', 'email', 'password1', 'password2', 'terms_consent',]
def __init__(self, *args, **kwargs):
super(SignupForm, self).__init__(*args, **kwargs)
self.fields['terms_consent'].widget.attrs['class'] = ''
self.fields['terms_consent'].widget.attrs['type'] = 'checkbox'
self.helper = FormHelper()
self.helper.layout = Layout(
CustomCheckbox('is_age_compliant'),
)
pass
def save(self, request):
user = super().save(request)
profile = Profile(user=user,terms_consent=True)
user.save()
profile.save()
return user
class Meta:
model = Profile
fields = ('terms_consent')
Signup.html:
<form class="signup" id="signup_form" autocomplete="off" method="post" action="{% url 'account_signup' %}">
{% csrf_token %}
{{ form.username|as_crispy_field }}
{{ form.email|as_crispy_field }}
{{ form.password1|as_crispy_field }}
{{ form.password2|as_crispy_field }}
{{ form.terms_consent|as_crispy_field }}
{% if redirect_field_value %}
<input type="hidden" name="{{ redirect_field_name }}" value="{{ redirect_field_value }}" />
{% endif %}
<button type="submit" class="btn btn-primary form-control">{% trans "Sign Up" %} »</button>
</form>
Custom Checkbox.html:
{% load crispy_forms_field %}
<div class="form-group">
<div class="custom-control custom-checkbox">
{% crispy_field field 'class' 'custom-control-input' %}
<label class="custom-control-label" for="{{ field.id_for_label }}">{{ field.label }}</label>
</div>
</div>
Settings.py:
ACCOUNT_FORMS = {
'signup': 'app.forms.SignupForm',
}
Models.py:
class Profile(models.Model):
user = models.OneToOneField(User, related_name='profile', on_delete=models.CASCADE)
terms_consent = models.BooleanField(default=False, blank=True, null=True,)
def __str__(self):
return self.user.username
In 2.0.3 when I login and then accept the terms, I am unable to view any HTML content for the terms that this github project normally produces from the database entries. It just shows a blank page at /terms/ after accepting. When rolling back to 2.0.2, it works again and I am able to view the HTML content at /terms/ again after accepting.
If needed, perhaps rolling back this project back to 2.0.2 would be best. Regarding my previous issue, now I know that it is necessary to not re-name the slug to anything else other than site-terms so I do not mind reverting back to 2.0.2. The maintainer team of this project needs to decide moving forward whether they want to prevent accidental / custom changes to the slug in admin or in settings. Maybe make it a disabled field in admin. It would have been nice though to make your own custom slug but if not, so be it. If reverting back to 2.0.2, I highly recommend updating the documentation with a warning saying "Do not change the slug to anything other than site-terms".
from future import unicode_literals
from django.db import models
from django.contrib.auth.models import User
from django.contrib.sites.models import Site
from six import python_2_unicode_compatible
@python_2_unicode_compatible
class Product(models.Model):
"""A generic Product"""
name = models.CharField(blank=True, max_length=100)
sites = models.ManyToManyField(Site)
def __str__(self):
return self.name
@models.permalink
def get_absolute_url(self):
return ('product_detail', [self.id])
def sites_str(self):
return ', '.join([s.name for s in self.sites.all()])
sites_str.short_description = 'sites'
@python_2_unicode_compatible
class Vote(models.Model):
"""A Vote on a Product"""
user = models.ForeignKey(User, related_name='votes')
product = models.ForeignKey(Product)
site = models.ForeignKey(Site)
score = models.FloatField()
def __str__(self):
return "Vote"
Hi, how I capture the signal after accept terms to send email?
(IPs have been modified)
For an unknown reason, there are sometimes 2 IP addresses and the insert in database crashes because of that.
I'm using TERMS_IP_HEADER_NAME = "HTTP_X_FORWARDED_FOR"
Maybe we can just split on ", " and only save the first IP address.
Complete stack trace:
ERROR:django.request:Internal Server Error: /terms/accept/
Traceback (most recent call last):
File "/usr/local/lib/python3.7/site-packages/django/db/backends/utils.py", line 84, in _execute
return self.cursor.execute(sql, params)
psycopg2.errors.InvalidTextRepresentation: invalid input syntax for type inet: "88.126.6.206, 165.225.76.60"
LINE 1: ..., "ip_address", "date_accepted") VALUES (2066, 2, '85.136.1....
^
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "/usr/local/lib/python3.7/site-packages/django/core/handlers/exception.py", line 34, in inner
response = get_response(request)
File "/usr/local/lib/python3.7/site-packages/django/core/handlers/base.py", line 115, in _get_response
response = self.process_exception_by_middleware(e, request)
File "/usr/local/lib/python3.7/site-packages/django/core/handlers/base.py", line 113, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/usr/local/lib/python3.7/site-packages/django/views/generic/base.py", line 71, in view
return self.dispatch(request, *args, **kwargs)
File "/usr/local/lib/python3.7/site-packages/django/views/generic/base.py", line 97, in dispatch
return handler(request, *args, **kwargs)
File "/usr/local/lib/python3.7/site-packages/termsandconditions/views.py", line 134, in post
new_user_terms.save()
File "/usr/local/lib/python3.7/site-packages/django/db/models/base.py", line 741, in save
force_update=force_update, update_fields=update_fields)
File "/usr/local/lib/python3.7/site-packages/django/db/models/base.py", line 779, in save_base
force_update, using, update_fields,
File "/usr/local/lib/python3.7/site-packages/django/db/models/base.py", line 870, in _save_table
result = self._do_insert(cls._base_manager, using, fields, update_pk, raw)
File "/usr/local/lib/python3.7/site-packages/django/db/models/base.py", line 908, in _do_insert
using=using, raw=raw)
File "/usr/local/lib/python3.7/site-packages/django/db/models/manager.py", line 82, in manager_method
return getattr(self.get_queryset(), name)(*args, **kwargs)
File "/usr/local/lib/python3.7/site-packages/django/db/models/query.py", line 1186, in _insert
return query.get_compiler(using=using).execute_sql(return_id)
File "/usr/local/lib/python3.7/site-packages/django/db/models/sql/compiler.py", line 1375, in execute_sql
cursor.execute(sql, params)
File "/usr/local/lib/python3.7/site-packages/django/db/backends/utils.py", line 67, in execute
return self._execute_with_wrappers(sql, params, many=False, executor=self._execute)
File "/usr/local/lib/python3.7/site-packages/django/db/backends/utils.py", line 76, in _execute_with_wrappers
return executor(sql, params, many, context)
File "/usr/local/lib/python3.7/site-packages/django/db/backends/utils.py", line 84, in _execute
return self.cursor.execute(sql, params)
File "/usr/local/lib/python3.7/site-packages/django/db/utils.py", line 89, in __exit__
raise dj_exc_value.with_traceback(traceback) from exc_value
File "/usr/local/lib/python3.7/site-packages/django/db/backends/utils.py", line 84, in _execute
return self.cursor.execute(sql, params)
django.db.utils.DataError: invalid input syntax for type inet: "85.136.1.206, 125.228.71.64"
LINE 1: ..., "ip_address", "date_accepted") VALUES (2066, 2, '85.136.1....
Hitting the change
link in the User Terms and Conditions
of Django admin, I receive the following error:
I have a custom user model where users authenticate using their email instead of a username along the lines of django docs, if I remember well.
I can post the whole structure if needed.
Environment:
Request Method: GET
Request URL: http://127.0.0.1:8000/<my-custom-url>/admin/termsandconditions/usertermsandconditions/
Django Version: 1.11.4
Python Version: 3.4.2
Traceback:
File "/home/user/.virtualenvs/environment/lib/python3.4/site-packages/django/db/backends/utils.py" in execute
65. return self.cursor.execute(sql, params)
The above exception (target lists can have at most 1664 entries
) was the direct cause of the following exception:
File "/home/user/.virtualenvs/environment/lib/python3.4/site-packages/django/core/handlers/exception.py" in inner
41. response = get_response(request)
File "/home/user/.virtualenvs/environment/lib/python3.4/site-packages/django/core/handlers/base.py" in _get_response
187. response = self.process_exception_by_middleware(e, request)
File "/home/user/.virtualenvs/environment/lib/python3.4/site-packages/django/core/handlers/base.py" in _get_response
185. response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/home/user/.virtualenvs/environment/lib/python3.4/site-packages/django/contrib/admin/options.py" in wrapper
551. return self.admin_site.admin_view(view)(*args, **kwargs)
File "/home/user/.virtualenvs/environment/lib/python3.4/site-packages/django/utils/decorators.py" in _wrapped_view
149. response = view_func(request, *args, **kwargs)
File "/home/user/.virtualenvs/environment/lib/python3.4/site-packages/django/views/decorators/cache.py" in _wrapped_view_func
57. response = view_func(request, *args, **kwargs)
File "/home/user/.virtualenvs/environment/lib/python3.4/site-packages/django/contrib/admin/sites.py" in inner
224. return view(request, *args, **kwargs)
File "/home/user/.virtualenvs/environment/lib/python3.4/site-packages/django/utils/decorators.py" in _wrapper
67. return bound_func(*args, **kwargs)
File "/home/user/.virtualenvs/environment/lib/python3.4/site-packages/django/utils/decorators.py" in _wrapped_view
149. response = view_func(request, *args, **kwargs)
File "/home/user/.virtualenvs/environment/lib/python3.4/site-packages/django/utils/decorators.py" in bound_func
63. return func.__get__(self, type(self))(*args2, **kwargs2)
File "/home/user/.virtualenvs/environment/lib/python3.4/site-packages/django/contrib/admin/options.py" in changelist_view
1662. selection_note=_('0 of %(cnt)s selected') % {'cnt': len(cl.result_list)},
File "/home/user/.virtualenvs/environment/lib/python3.4/site-packages/django/db/models/query.py" in __len__
232. self._fetch_all()
File "/home/user/.virtualenvs/environment/lib/python3.4/site-packages/django/db/models/query.py" in _fetch_all
1118. self._result_cache = list(self._iterable_class(self))
File "/home/user/.virtualenvs/environment/lib/python3.4/site-packages/django/db/models/query.py" in __iter__
53. results = compiler.execute_sql(chunked_fetch=self.chunked_fetch)
File "/home/user/.virtualenvs/environment/lib/python3.4/site-packages/django/db/models/sql/compiler.py" in execute_sql
894. raise original_exception
File "/home/user/.virtualenvs/environment/lib/python3.4/site-packages/django/db/models/sql/compiler.py" in execute_sql
884. cursor.execute(sql, params)
File "/home/user/.virtualenvs/environment/lib/python3.4/site-packages/django/db/backends/utils.py" in execute
80. return super(CursorDebugWrapper, self).execute(sql, params)
File "/home/user/.virtualenvs/environment/lib/python3.4/site-packages/django/db/backends/utils.py" in execute
65. return self.cursor.execute(sql, params)
File "/home/user/.virtualenvs/environment/lib/python3.4/site-packages/django/db/utils.py" in __exit__
94. six.reraise(dj_exc_type, dj_exc_value, traceback)
File "/home/user/.virtualenvs/environment/lib/python3.4/site-packages/django/utils/six.py" in reraise
685. raise value.with_traceback(tb)
File "/home/user/.virtualenvs/environment/lib/python3.4/site-packages/django/db/backends/utils.py" in execute
65. return self.cursor.execute(sql, params)
Exception Type: OperationalError at /<my-custom-url>/admin/termsandconditions/usertermsandconditions/
Exception Value: target lists can have at most 1664 entries
I've checked the guideline on this package to make the translations and I don't know if I'm doing something wrong or maybe the guidelines are outdated (because they are from 2015).
I could make the point 1 and point 2, but when trying to make the point 3. Add translation
, when running the makemigrations
command I get the following message:
No changes detected in app 'termsandconditions'
I attach my code blocks related to this implementation:
settings.py
LANGUAGES = (
('en', _('English')),
('es', _('Spanish')),
)
MIGRATION_MODULES = {
# local path for migration for the termsandconditions
'termsandconditions': 'ToS_translations.migrations.migrations_termsandconditions',
}
translation.py
from modeltranslation.translator import translator, TranslationOptions
from termsandconditions.models import TermsAndConditions
class TermsAndConditionsTranslationOptions(TranslationOptions):
fields = ('name', 'text', 'info')
translator.register(TermsAndConditions, TermsAndConditionsTranslationOptions)
The structure of my project
-my_project
- my_project
- settings.py
- ...
- ToS_translations
- migrations
- migrations_termsandconditions
- 001_initial.py
- __init__.py
- __init__.py
- __init__.py
- translation.py
- other_apps
Thank you.
I'm trying to install the package to another computer which is using the same packages as the first one I got it installed and I'm having an error.
Information of the system:
Python 3.6
Django 2.2
PostgreSQL 12
The error:
Collecting django-termsandconditions==2.0.6
Using cached django-termsandconditions-2.0.6.tar.gz (22 kB)
Installing build dependencies: started
Installing build dependencies: finished with status 'done'
Getting requirements to build wheel: started
Getting requirements to build wheel: finished with status 'error'
DEPRECATION: The -b/--build/--build-dir/--build-directory option is deprecated. pip 20.3 will remove support for this functionality. A possible replacement is use the TMPDIR/TEMP/TMP environment variable, possibly combined with --no-clean. You can find discussion regarding this at https://github.com/pypa/pip/issues/8333.
ERROR: Command errored out with exit status 1:
command: /Users/juanjo/PycharmProjects/ekiterplatform/venv/bin/python /Users/juanjo/PycharmProjects/ekiterplatform/venv/lib/python3.6/site-packages/pip/_vendor/pep517/_in_process.py get_requires_for_build_wheel /var/folders/lh/5bwwxr2911z513712wt71l_80000gn/T/tmpdy3s1mne
cwd: /private/var/folders/lh/5bwwxr2911z513712wt71l_80000gn/T/pycharm-packaging/django-termsandconditions
Complete output (10 lines):
Traceback (most recent call last):
File "/Users/juanjo/PycharmProjects/ekiterplatform/venv/lib/python3.6/site-packages/pip/_vendor/pep517/_in_process.py", line 280, in <module>
main()
File "/Users/juanjo/PycharmProjects/ekiterplatform/venv/lib/python3.6/site-packages/pip/_vendor/pep517/_in_process.py", line 263, in main
json_out['return_val'] = hook(**hook_input['kwargs'])
File "/Users/juanjo/PycharmProjects/ekiterplatform/venv/lib/python3.6/site-packages/pip/_vendor/pep517/_in_process.py", line 108, in get_requires_for_build_wheel
backend = _build_backend()
File "/Users/juanjo/PycharmProjects/ekiterplatform/venv/lib/python3.6/site-packages/pip/_vendor/pep517/_in_process.py", line 99, in _build_backend
obj = getattr(obj, path_part)
AttributeError: module 'setuptools.build_meta' has no attribute '__legacy__'
----------------------------------------
ERROR: Command errored out with exit status 1: /Users/juanjo/PycharmProjects/ekiterplatform/venv/bin/python /Users/juanjo/PycharmProjects/ekiterplatform/venv/lib/python3.6/site-packages/pip/_vendor/pep517/_in_process.py get_requires_for_build_wheel /var/folders/lh/5bwwxr2911z513712wt71l_80000gn/T/tmpdy3s1mne Check the logs for full command output.
If I try to uninstall and reinstall the package on the other computer it works just fine.
If you need any extra information please ask for it. Thank you
We would like to have two kinds of permissions. The first should be mandatory for using the site.
I've seen that this should be easily done with this package by using a middleware.
We would like to have a second kind if terms of conditions, where we ask our user for their permission to use their measurement data for scientific analyses. Agreeing to this second T&C should be optional, so the users should be able to use the site also if they do not give us their permission.
Is this possible out of the box?
I've seen that when using the middleware, all "active" T&Cs must be confirmed for using the site.
If we created this second T&C as "not active", would it be possible to ask users on first login whether they agree to it or not?
Seems like applications is not working correct with language code in urls.
For example settings config to:
TERMS_EXCLUDE_URL_LIST = ('/', '/terms/required/', '/logout', '/securetoo/')
doesn't trigger for actual logout url - /{language_code}/logout/
NoReverseMatch at /terms/
Reverse for 'tc_print_page' with arguments '('', '')' not found. 1 pattern(s) tried: ['terms/print/(?P[a-zA-Z0-9_.-]+)/(?P[0-9.]+)/$']
"GET /terms/ HTTP/1.1" 500 178082
Requested Terms and Conditions that Have Not Been Created.
Internal Server Error: /terms/
After navigating to 127.0.0.1:8000/terms/ I received the error above.
All of these other URLs work however after adding data to the terms and conditions models inside 127.0.0.1:8000/admin/:
/terms/print/terms_slug/1.0/
/terms/view/terms_slug/1.0/
/terms/email/
/terms/accept/
I am using Django 3.0.3, Python 3.7.3, and the latest version of django-termsandconditions 2.0.2.
In version 2.0 of django-termsandconditions in combination with Django 2.2.9 and Sqlite (not sure exactly if the Django version / database is to blame or the newly added django-termsandconditions project update for the error above), I was able to navigate to /terms/ without a problem as well as the other URL endings above.
In addition to this error, I want to point out that the build for this project says build error and "some check were not successful" and pyup has 4 updates as well. Maybe this problem is related to this? Otherwise please fix these as well as it makes people hesitant to install this project since github is displaying this to users.
I would also like for this project to work on the latest Django 3 and Python 3 and be Postgres 12 compatible. This error might be showing up because of my recent move to Postgres 12 and upgrade to Django 3.0.3 or because the this project was updated a few days ago. Not sure.
Noticed that on some of the templates with target="_blank" it is vulnerable to reverse tabnapping since it is missing rel="noopener noreferrer".
https://developers.google.com/web/tools/lighthouse/audits/noopener
However, this may not be a concern if users choose to override the templates.
The main difference I can see is the stripping of the bytestrings?
# -*- coding: utf-8 -*-
# Generated by Django 1.11.2 on 2017-06-27 07:12
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('termsandconditions', '0002_termsandconditions_info'),
]
operations = [
migrations.AlterField(
model_name='termsandconditions',
name='date_active',
field=models.DateTimeField(blank=True, help_text='Leave Null To Never Make Active', null=True),
),
migrations.AlterField(
model_name='termsandconditions',
name='info',
field=models.TextField(blank=True, help_text="Provide users with some info about what's changed and why", null=True),
),
migrations.AlterField(
model_name='termsandconditions',
name='slug',
field=models.SlugField(default='site-terms'),
),
migrations.AlterField(
model_name='usertermsandconditions',
name='date_accepted',
field=models.DateTimeField(auto_now_add=True, verbose_name='Date Accepted'),
),
migrations.AlterField(
model_name='usertermsandconditions',
name='ip_address',
field=models.GenericIPAddressField(blank=True, null=True, verbose_name='IP Address'),
),
]
On a separate note, would you be open to a PR which excludes Users from accepting terms if they have a certain permission?
There's a problematic statement at https://github.com/cyface/django-termsandconditions/blob/master/termsandconditions/forms.py#L13:
terms = forms.ModelMultipleChoiceField(
TermsAndConditions.get_active_list(as_dict=False),
widget=forms.MultipleHiddenInput,
)
where the TermsAndConditions.get_active_list
returns a list of current terms in the database. I've run into a problem where this fails during unit tests when there is no database available and not used at all (using py.test for a set of tests that do not use models at all). This is because the code above tries to access a non-existent database.
Looking here there are also some other problems, so:
terms
field (which was loaded earlier)I think the solution would be to move settings terms
field within the class constructor instead (there's already such action in https://github.com/cyface/django-termsandconditions/blob/master/termsandconditions/forms.py#L24 for handling a case with explicit list). Any thoughts on this?
It is possible by slug, but decorator check only DEFAULT_TERMS_SLUG:
TermsAndConditions.agreed_to_latest(request.user)
def agreed_to_latest(user, slug=DEFAULT_TERMS_SLUG):
We don't want to store our users' IP addresses... would you be open to adding a setting to disable that feature?
I guess this is a general question but this package has a lot of links and some of them have duplicate content.
Which links should be included in sitemap.xml and disallowed in robots.txt?
Some of the URLs can be accessed when the user is logged out and logged in. For instance, /terms/accept/, /terms/accept/site-terms/, /terms/accept/site-terms/version_number/ can all be accessed when logged out which doesn't make sense logically but I guess it is fine and doesn't need a code change as long as pressing accept does not do anything when logged out and logged in (only after previously accepting another time).
Google bot will probably see these links so I guess this would be a good way to do it?
sitemap.xml:
<url>
<loc>http://example.com/terms/view/site-terms/</loc>
<changefreq>always</changefreq>
<priority>0.9</priority>
</url>
Robot.txt:
Disallow:
/terms/
/terms/active/
/terms/accept/
/terms/accept/site-terms/
/terms/accept/site-terms/version_number/
/terms/view/site-terms/version_number/
/terms/email/
/terms/email/site-terms/version_number/
/terms/print/site-terms/version_number/
Off topic rant: If you were to make some of those views @login_required, it may have a conflict with django-allauth and django-two-factor-auth I discovered in some of my other issue reports if those packages are used together where a logged out user could access django-two-factor-auth admin login page from a valid login only view URL. (so i don't mind if you don't change the code because of this)
Hello,
We implemented django-termsandconditions in two projects and both have issues when users accept the T&C, sometimes happen:
In all cases the registry of acceptance is correctly added in the DB.
settings.py:
# Terms and conditions setup
TERMS_BASE_TEMPLATE = 'web_manager/base.html'
TERMS_EXCLUDE_URL_CONTAINS_LIST = {'/terms/', '/i18n/setlang/', }
TERMS_CACHE_SECONDS = 30 # 10 in the other project
MIGRATION_MODULES = {
# local path for migration for the termsandconditions
'termsandconditions': 'company.migrations.migrations_termsandconditions',
}
If developers provide an email, we can share a private video with the issues.
Thanks.
This is a feature request. To avoid filling up the database with additional user acceptances every time the terms get updated, why not delete the previous user acceptances and only keep the acceptances for that user regarding the latest version that they just accepted? Only delete the previous acceptances for that user if they accept the newest terms version. If they have not yet accepted the newest terms version, keep the old acceptance entry logged in the database still.
To satisfy all people who use django-termsandconditions, a setting like DELETE_OLD_ON_ACCEPT=True|False or whatever you want to call it would be needed for this to turn this on or off. Because maybe tracking all user acceptances in the database is needed no matter what the version of the terms is and maybe for legal purposes old acceptances would be needed to remain tracked in the database?
Example:
User accepts version 1
User version 1 acceptance logged in the database
Terms updates to version 2
Same user accepts version 2
Same user acceptance from version 1 in the database gets deleted
Version 2 acceptance gets logged in the database for that user
Hello! I have a use case for having multiple terms for a site, but active within different contexts, such as depending on a user's role. So, I would want one set of terms active for the site for all users, but if a user is requesting access to particular functionality or other roles on the site, they may have to accept additional terms and conditions.
I've dealt with this for now by creating a second terms document but not activating it (i.e., the active dates are Null). Then, I wrote a new decorator that allows me to specify a specific terms slug required for that view. This activates that single terms for acceptance. It would be nice if there were a cleaner way to have terms active, but not "default" terms for all users.
The decorator I'm using:
import urlparse
from functools import wraps
from django.conf import settings
from django.core.urlresolvers import reverse
from django.http import HttpResponseRedirect, QueryDict
from django.utils.decorators import available_attrs
from termsandconditions.models import TermsAndConditions, UserTermsAndConditions
def terms_required(terms_slug):
def decorator(view_func):
"""
This decorator checks to see if the user is logged in, and if so, if they have accepted the site terms.
"""
@wraps(view_func, assigned=available_attrs(view_func))
def _wrapped_view(request, *args, **kwargs):
"""Method to wrap the view passed in"""
terms = TermsAndConditions.objects.filter(slug=terms_slug)[0]
if not request.user.is_authenticated() or _agreed_to_terms( request.user, terms ):
return view_func(request, *args, **kwargs)
currentPath = request.META['PATH_INFO']
accept_path = reverse( 'tc_accept_specific_version_page', args=[ terms.slug, terms.version_number ] )
login_url_parts = list(urlparse.urlparse(accept_path))
querystring = QueryDict(login_url_parts[4], mutable=True)
querystring['returnTo'] = currentPath
login_url_parts[4] = querystring.urlencode(safe='/')
return HttpResponseRedirect(urlparse.urlunparse(login_url_parts))
return _wrapped_view
return decorator
def _agreed_to_terms( user, terms ):
try:
UserTermsAndConditions.objects.get(user=user, terms=terms)
return True
except UserTermsAndConditions.MultipleObjectsReturned:
return True
except UserTermsAndConditions.DoesNotExist:
return False
Hi,
I came across a use case, where a ToS text has to include other variables and e.g. urls defined by {% url 'my-url-name' %}
. In general, the ToS text (or other field) could contain template-like syntax.
This could be done by including a terms.text
in a form of a Template object and using the include
tag. Thus, one would need to customize the respective template file and use there {% include terms.text|as_template %}
instead of {{ terms.text|safe }}
.
I can do a PR with an additional template tag, and help info. Let me know if you think this makes sense.
Are there any plans to support Django 1.10 and up?
A quick test against 1.11 gave the following stacktrace:
File "/opt/master/venv/lib/python3.6/site-packages/django/core/handlers/base.py", line 82, in load_middleware
mw_instance = middleware(handler)
TypeError: object() takes no parameters
If a not logged in user, accesses <site-url>/terms
the terms will be shown.
Is it possible to allow the showing of the terms only to logged-in users?
Otherwise, is it possible to change the terms
slug to something like <site-url>/blah/blah/terms
?
Hi there,
is there a possibility to integrate easy into forms?
I mean that user accept the tac
Are you planning to update to Django 2.2? Our development team really likes django-termsandconditions and want to be able to use it.
MIssing from the documentation is a minimum custom template which caters for the terms and coditions.
It can be activated in the settings.py:
TERMS_BASE_TEMPLATE = 'admin/terms.html'
admin/terms.html
<!DOCTYPE html>
<html>
<head>
<title>[My Title]</title>
{% block styles %}{% endblock %}
<link href='<path-to-my-css>' rel='stylesheet' type='text/css' />
</head>
<body>
<main>
<h2>{% block title %}{% endblock %}</h2>
{% block content %}{% endblock %}
</main>
</body>
</html>
The only issue is that the block title
is wrapped between h2
tags since the block content
includes an h1
tag already.
Do you plan to support newlines and other formatting in the terms and conditions?
This is kind of a dumb question. But would like to hear your thoughts. Feel free to close this issue if the answer is no.
Does the form on this page need a captcha / honeypot field to stop spam? The only thing a user / bot could really do is click accept to the terms and conditions and they can't really do anything else. But since it is a form I am not sure.
First, thanks for this package.
Python 3.5/3.6 are still supported (in security mode): https://devguide.python.org/#status-of-python-branches. Django 2.2 also supports Python 3.5 and 3.6: https://docs.djangoproject.com/en/2.2/releases/2.2/#python-compatibility. Would you be open to a PR that re-adds support for them to this package (or at least for Python 3.6)?
You can force protection of your whole site by using the T&C middleware. Once activated, any attempt to access an authenticated page will first check to see if the user has accepted the active T&Cs. This can be a performance impact, so you can also use the _TermsAndConditionsDecorator to protect specific views, or the pipeline setup to only check on account creation.
I read the warning. However, I use django-debug-toolbar and I see that middleware use causes 7 extra queries, while 5 of them are duplicated 5 times. Is this OK?
The same number of queries appears when I use {% show_terms_if_not_agreed %}
in the base.html
template.
File ".../lib/python3.6/site-packages/termsandconditions/models.py", line 63, in TermsAndConditions
@models.permalink
AttributeError: module 'django.db.models' has no attribute 'permalink'
Django 2.1 has removed the permalink() decorator.
I think a fix would be something like:
from django.urls import reverse
...
def get_absolute_url(self):
return reverse(
'tc_view_specific_version_page',
args=[self.slug, self.version_number]) # pylint: disable=E1101
Thanks for this app!
Thanks for this package! I'm interested in using it for a web application for scientists in a particular field and I'm wondering what kind of license you want to choose for your package. Is it already decided?
I've been trying to get a clean lot output, but I see this in my debug logs
2019-08-11 13:19:47,896 django.channels.server DEBUG Daphne running, listening on 127.0.0.1:8000
2019-08-11 13:30:05,301 django.template DEBUG Exception while resolving variable 'not_agreed_terms' in template 'home/home_page.html'.
Traceback (most recent call last):
File "/Volumes/sharpertool/proj/gardentronic/gardentronic/.venv3/lib/python3.7/site-packages/django/template/base.py", line 829, in _resolve_lookup
current = current[bit]
File "/Volumes/sharpertool/proj/gardentronic/gardentronic/.venv3/lib/python3.7/site-packages/django/template/context.py", line 83, in __getitem__
raise KeyError(key)
KeyError: 'not_agreed_terms'
During handling of the above exception, another exception occurred:
* THIS GOES ON FOR A LONG TIME *
It drove me crazy for a while, but I finally tracked it down to this the inclusion tag "show_terms_if_not_agreed"
The tag has this logic
if not_agreed_terms and is_path_protected(url.path):
return {'not_agreed_terms': not_agreed_terms, 'returnTo': url.path}
else:
return {}
The problem is that it returns without the value set for 'not_agreed_terms', and so that means that the snippet, which includes this:
{% if not_agreed_terms %}
{% render_bundle 'terms_modal' 'css' 'ASSETS' %}
Will raise a template Exception unless the user has NOT agreed to terms, basically, all of the time.
if not_agreed_terms and is_path_protected(url.path):
return {'not_agreed_terms': not_agreed_terms, 'returnTo': url.path}
else:
return {'not_agreed_terms': False}
This cleans up the error logs, and it's a cleaner solution anyway. Oh, and it likely improves performance since the Django stack does not need to unwind a bunch of stack frames.
The email form in /terms/email/ and /terms/email/site-terms/version_number/ is not working.
I actually do not need this feature at all and maybe including a setting to disable these links / form is a good idea?
I suppose if they do not work that is fine as long as it cannot be compromised by a hacker / spam bots.
Thanks for the great package! I recently upgraded to Django 2.0.13. Would it be possible to add:
app_name = 'terms_and_conditions'
to line 13 of the urls.py file to enable namespaces for Django-termsandconditions?
Thanks!
pip has 1.1.14 which is not tagged in github. This makes it hard to follow what is part of the release. Or is development happenning elsewhere?
Thanks a lot.
Hi! Great module so far. But it seems like some prettiness is missing. Can you include wysiwyg editor for T&C? Or i can create pull request i guess
Now that the user could use any custom slug name, there needs to be a way to define that new custom slug name in settings so that every time a user changes the slug in admin, settings will be updated automatically.
For example, instead of:
TERMS_EXCLUDE_URL_LIST = {'/terms/accept/site-policy/'}
Do something like (using regular expressions):
TERMS_EXCLUDE_URL_LIST = {'/terms/accept/.*/'}
Not sure if this is currently possible using the current code or not. Please let me know.
The reason I want to do this is because I am running this project twice in my Django project. Once is for my site's terms and conditions and the other time is for my site's privacy policy. I would love if this project had an exact github package copy but for privacy policy. Where any code change in the terms and conditions github would need to be changed in the privacy policy github and vice versa. If not, no big deal I will just have to copy this terms and conditions project and change the variables to privacy policy ones myself and add to my django project as an app every time there is an update to the code.
Note for other users who want to run this project twice: in the TERMS_EXCLUDE_URL_LIST and POLICY_EXCLUDE_URL_LIST (this I made from changing the variables) there needs to be an exclusion of every policy URL in the TERMS_EXCLUDE_URL_LIST like this: TERMS_EXCLUDE_URL_LIST = {'/policyrequired/', '/policy/', '/policy/accept/', '/policy/accept/site-policy/'} in order to run both projects at the same time.
Can you change this line
ip_address = request.META.get(‘HTTP_X_FORWARDED_FOR’, ”) or request.META.get(‘REMOTE_ADDR’)
because when you are using nginx, REMOTE_ADDR is not present
Thanks for this package - we've been using a fork of it.
I just installed django-termsandconditions from PyPI, and it upgraded my django 1.8 to 1.9. Looks like that's required in setup.py. Is it intentional to not support 1.8 LTS?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.