diff --git a/requirements.txt b/requirements.txt
index 49a543a076f30f5d39b61889939d1ecfedebdedc..03297a8dc9e83fa4bd3869ed53f19306a9589418 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -35,7 +35,7 @@ numpy==1.19.2
 pandas==1.1.3
 django-datatables-view==1.19.1
 phonenumberslite==8.9.14
-Pillow==3.4.2
+Pillow==8.0.1
 psycopg2==2.8.6
 pycparser==2.19
 pyexcel==0.6.4
@@ -60,3 +60,4 @@ urllib3==1.23
 whitenoise==5.2.0
 xlrd==1.1.0
 xlwt==1.3.0
+parameterized==0.7.4
\ No newline at end of file
diff --git a/smash/smash/settings.py b/smash/smash/settings.py
index 0b20f9916893b6e782d9aed6fe15fe898a3ae558..e147adf43a7ce463b52595802204d800ad3094ea 100644
--- a/smash/smash/settings.py
+++ b/smash/smash/settings.py
@@ -49,6 +49,7 @@ INSTALLED_APPS = [
 ]
 
 MIDDLEWARE = [
+    'web.middleware.PrivacyNoticeMiddleware',
     'debug_toolbar.middleware.DebugToolbarMiddleware',
     'django.middleware.security.SecurityMiddleware',
     'whitenoise.middleware.WhiteNoiseMiddleware',
diff --git a/smash/web/api_urls.py b/smash/web/api_urls.py
index 11a02b7b4c553ecb41c5a1272502ab437bf93e3d..a3baf7356589b4d8dc08a3a592fcad90467d458d 100644
--- a/smash/web/api_urls.py
+++ b/smash/web/api_urls.py
@@ -64,6 +64,7 @@ urlpatterns = [
 
     url(r'^workers/add_extra_availability/(?P<worker_id>\d+)/(?P<start_str_date>\d{4}-\d{2}-\d{2}-\d{2}-\d{2})/(?P<end_str_date>\d{4}-\d{2}-\d{2}-\d{2}-\d{2})/$', 
         worker.add_worker_extra_availability, name='web.api.workers.add_extra_availability'),
+    url(r'^worker/accept_privacy_notice/$', worker.accept_privacy_notice, name='web.api.workers.accept_privacy_notice'),
 
     # daily planning data
     url(r'^daily_planning/workers/$', worker.workers_for_daily_planning, name='web.api.workers.daily_planning'),
diff --git a/smash/web/api_views/worker.py b/smash/web/api_views/worker.py
index c956782d4377bb8d365a58dd892aaefcdf429ac0..2ecf1a00a7bb9090abb12a7e34c058bef1049802 100644
--- a/smash/web/api_views/worker.py
+++ b/smash/web/api_views/worker.py
@@ -26,6 +26,15 @@ def units(request):
         "units": [x[0] for x in workers]
     })
 
+
+def accept_privacy_notice(request):
+    worker = Worker.get_by_user(request.user)
+    worker.privacy_notice_accepted = True
+    worker.save()
+    return JsonResponse({
+        "status": 'ok'
+    })
+
 def workers_for_daily_planning(request):
     start_date = request.GET.get('start_date')
     workers = get_workers_for_daily_planning(request)
diff --git a/smash/web/forms/__init__.py b/smash/web/forms/__init__.py
index 698f27b4f65ea900c87815a3ffa6fb3b6f08697d..fe81e129a4d942bdb713f4e19f24ccf4a47d9191 100644
--- a/smash/web/forms/__init__.py
+++ b/smash/web/forms/__init__.py
@@ -1,5 +1,5 @@
 from .study_forms import StudyEditForm, StudyNotificationParametersEditForm, StudyColumnsEditForm, StudyRedCapColumnsEditForm
-from .worker_form import WorkerForm
+from .worker_form import WorkerForm, WorkerAcceptPrivacyNoticeForm
 from .forms import VisitDetailForm, \
     VisitAddForm, KitRequestForm, StatisticsForm, AvailabilityAddForm, \
     AvailabilityEditForm, HolidayAddForm
@@ -8,10 +8,11 @@ from .appointment_form import AppointmentDetailForm, AppointmentEditForm, Appoin
 from .study_subject_forms import StudySubjectAddForm, StudySubjectDetailForm, StudySubjectEditForm
 from .subject_forms import SubjectAddForm, SubjectEditForm, SubjectDetailForm
 from .voucher_forms import VoucherTypeForm, VoucherTypePriceForm, VoucherForm
+from .privacy_notice import PrivacyNoticeForm
 
 __all__ = [StudySubjectAddForm, StudySubjectDetailForm, StudySubjectEditForm, WorkerForm,
            AppointmentDetailForm, AppointmentEditForm, AppointmentAddForm, VisitDetailForm, VisitAddForm,
            ContactAttemptAddForm, ContactAttemptEditForm, KitRequestForm, StatisticsForm, AvailabilityAddForm,
            AvailabilityEditForm, HolidayAddForm, SubjectAddForm, SubjectEditForm, SubjectDetailForm, VoucherTypeForm,
            VoucherTypePriceForm, VoucherForm, StudyEditForm, StudyNotificationParametersEditForm, StudyColumnsEditForm, 
-           StudyRedCapColumnsEditForm]
+           StudyRedCapColumnsEditForm, PrivacyNoticeForm, WorkerAcceptPrivacyNoticeForm]
diff --git a/smash/web/forms/privacy_notice.py b/smash/web/forms/privacy_notice.py
new file mode 100644
index 0000000000000000000000000000000000000000..9394fe3687c142c54dbab9ef6d2b0e3c23ccf50e
--- /dev/null
+++ b/smash/web/forms/privacy_notice.py
@@ -0,0 +1,15 @@
+from django import forms
+from django.forms import ModelForm
+from web.models import PrivacyNotice
+
+import logging
+logger = logging.getLogger(__name__)
+
+class PrivacyNoticeForm(ModelForm):
+    class Meta:
+        model = PrivacyNotice
+        fields = '__all__'
+        
+    def clean(self):
+        cleaned_data = super().clean()
+        return cleaned_data
\ No newline at end of file
diff --git a/smash/web/forms/worker_form.py b/smash/web/forms/worker_form.py
index 25c4cc8df80a06ff60c6da7db42bd03dc45d6ec4..f82362938e92ed58bce1c113ec206699a5de5a7a 100644
--- a/smash/web/forms/worker_form.py
+++ b/smash/web/forms/worker_form.py
@@ -14,6 +14,19 @@ from web.decorators import PermissionDecorator
 
 logger = logging.getLogger(__name__)
 
+class WorkerAcceptPrivacyNoticeForm(ModelForm):
+    class Meta:
+        model = Worker
+        fields = ('privacy_notice_accepted', )
+
+    def __init__(self, *args, **kwargs):
+        super(WorkerAcceptPrivacyNoticeForm, self).__init__(*args, **kwargs)
+        self.fields['privacy_notice_accepted'].label = 'Do you accept the privacy notice?'
+
+    def clean(self):
+        cleaned_data = super().clean()
+        cleaned_data['privacy_notice_accepted'] = True
+        return cleaned_data
 
 class WorkerForm(ModelForm):
     class Meta:
@@ -63,7 +76,9 @@ class WorkerForm(ModelForm):
                 self.fields['Superuser'].initial = instance.user.is_superuser
             del self.fields['voucher_types']
             del self.fields['name']
+            self.fields['privacy_notice_accepted'].widget.attrs['readonly'] = True
         else:
+            del self.fields['privacy_notice_accepted']
             del self.fields['locations']
             del self.fields['first_name']
             del self.fields['last_name']
@@ -73,7 +88,7 @@ class WorkerForm(ModelForm):
 
         fields = OrderedDict()
 
-        if worker_type == WORKER_STAFF:
+        if worker_type == WORKER_STAFF:            
             if instance is None or instance.pk is None:
                 fields['login'] = forms.CharField(label='Login')
                 fields['password'] = forms.CharField(label='Password', widget=forms.PasswordInput)
diff --git a/smash/web/middleware.py b/smash/web/middleware.py
new file mode 100644
index 0000000000000000000000000000000000000000..e094a84f09c91c120fb0634d2b2e196c4a6cedea
--- /dev/null
+++ b/smash/web/middleware.py
@@ -0,0 +1,39 @@
+from django.contrib.auth.views import logout
+
+from web.models.constants import GLOBAL_STUDY_ID
+from web.models import Worker, Study
+from django.contrib import messages
+from django.urls import reverse
+from django.shortcuts import redirect
+from django.utils.deprecation import MiddlewareMixin
+from web.views.privacy_notice import privacy_notice_accept
+
+class PrivacyNoticeMiddleware(MiddlewareMixin):
+    #def __init__(self, get_response):
+        #self.get_response = get_response
+        # One-time configuration and initialization.
+    
+    def process_view(self, request, view_func, view_args, view_kwargs):
+        # Code to be executed for each request before
+        # the view (and later middleware) are called.
+
+        #response = self.get_response(request)
+        if request.user.is_authenticated \
+                and not view_func == privacy_notice_accept \
+                and not request.user.is_superuser \
+                and not view_func == logout:
+            study = Study.objects.filter(id=GLOBAL_STUDY_ID)[0]
+            worker = Worker.get_by_user(request.user)
+            if worker is None:
+                return None
+            if study.study_privacy_notice \
+                    and study.acceptance_of_study_privacy_notice_required \
+                    and not worker.privacy_notice_accepted\
+                    and study.study_privacy_notice.document.url != request.path:
+                messages.add_message(request, messages.WARNING, "You can't use the system until you accept the privacy notice.")
+                #return reverse_lazy('web.views.accept_privacy_notice', kwargs={'pk': study.study_privacy_notice})
+                return redirect(reverse('web.views.accept_privacy_notice', kwargs={'pk': study.study_privacy_notice.id}))
+
+        # Code to be executed for each request/response after
+        # the view is called.
+        return None 
\ No newline at end of file
diff --git a/smash/web/migrations/0177_auto_20201116_1508.py b/smash/web/migrations/0177_auto_20201116_1508.py
new file mode 100644
index 0000000000000000000000000000000000000000..969d1db84635e6c75d2604ae95110eea53085dd4
--- /dev/null
+++ b/smash/web/migrations/0177_auto_20201116_1508.py
@@ -0,0 +1,29 @@
+# Generated by Django 2.0.13 on 2020-11-16 15:08
+
+import django.core.files.storage
+import django.core.validators
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('web', '0176_configurationitem_local_setting_clean'),
+    ]
+
+    operations = [
+        migrations.CreateModel(
+            name='PrivacyNotice',
+            fields=[
+                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+                ('created_at', models.DateTimeField(auto_now_add=True)),
+                ('document', models.FileField(editable=False, upload_to='privacy_notices/', verbose_name='Study Privacy Notice file')),
+            ],
+        ),
+        migrations.AddField(
+            model_name='study',
+            name='study_privacy_notice',
+            field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='studies', to='web.PrivacyNotice', verbose_name='Study Privacy Note'),
+        )
+    ]
diff --git a/smash/web/migrations/0177_auto_20201116_1508_squashed_0180_auto_20201117_0838.py b/smash/web/migrations/0177_auto_20201116_1508_squashed_0180_auto_20201117_0838.py
new file mode 100644
index 0000000000000000000000000000000000000000..0ea6aaa3e07eff90c830ec708ad47c730bdaf199
--- /dev/null
+++ b/smash/web/migrations/0177_auto_20201116_1508_squashed_0180_auto_20201117_0838.py
@@ -0,0 +1,31 @@
+# Generated by Django 2.0.13 on 2020-11-17 08:48
+
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+    replaces = [('web', '0177_auto_20201116_1508'), ('web', '0178_auto_20201116_1513'), ('web', '0179_auto_20201116_1528'), ('web', '0180_auto_20201117_0838')]
+
+    dependencies = [
+        ('web', '0176_configurationitem_local_setting_clean'),
+    ]
+
+    operations = [
+        migrations.CreateModel(
+            name='PrivacyNotice',
+            fields=[
+                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+                ('created_at', models.DateTimeField(auto_now_add=True)),
+                ('document', models.FileField(editable=False, upload_to='privacy_notices/', verbose_name='Study Privacy Notice file')),
+                ('updated_at', models.DateTimeField(auto_now=True)),
+                ('name', models.CharField(default='', max_length=255, verbose_name='Name')),
+            ],
+        ),
+        migrations.AddField(
+            model_name='study',
+            name='study_privacy_notice',
+            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='studies', to='web.PrivacyNotice', verbose_name='Study Privacy Note'),
+        ),
+    ]
diff --git a/smash/web/migrations/0178_auto_20201116_1513.py b/smash/web/migrations/0178_auto_20201116_1513.py
new file mode 100644
index 0000000000000000000000000000000000000000..c3c4c4cc683cd3adc24cb7dbcbdf5d9421d8e3d5
--- /dev/null
+++ b/smash/web/migrations/0178_auto_20201116_1513.py
@@ -0,0 +1,21 @@
+# Generated by Django 2.0.13 on 2020-11-16 15:13
+
+import django.core.files.storage
+import django.core.validators
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('web', '0177_auto_20201116_1508'),
+    ]
+
+    operations = [
+        migrations.AddField(
+            model_name='privacynotice',
+            name='study',
+            field=models.ForeignKey(editable=False, null=True, on_delete=django.db.models.deletion.CASCADE, to='web.Study', verbose_name='Study'),
+        )
+    ]
diff --git a/smash/web/migrations/0179_auto_20201116_1528.py b/smash/web/migrations/0179_auto_20201116_1528.py
new file mode 100644
index 0000000000000000000000000000000000000000..da1ab045b22d246df336c1123b8be7f21ade2382
--- /dev/null
+++ b/smash/web/migrations/0179_auto_20201116_1528.py
@@ -0,0 +1,21 @@
+# Generated by Django 2.0.13 on 2020-11-16 15:28
+
+import django.core.files.storage
+import django.core.validators
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('web', '0178_auto_20201116_1513'),
+    ]
+
+    operations = [
+        migrations.AddField(
+            model_name='privacynotice',
+            name='updated_at',
+            field=models.DateTimeField(auto_now=True),
+        )
+    ]
diff --git a/smash/web/migrations/0179_merge_20201117_1048.py b/smash/web/migrations/0179_merge_20201117_1048.py
new file mode 100644
index 0000000000000000000000000000000000000000..036333dbf183e05258b8d8fd47f8e7b026452c96
--- /dev/null
+++ b/smash/web/migrations/0179_merge_20201117_1048.py
@@ -0,0 +1,14 @@
+# Generated by Django 2.0.13 on 2020-11-17 10:48
+
+from django.db import migrations
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('web', '0178_auto_20201116_1250'),
+        ('web', '0177_auto_20201116_1508_squashed_0180_auto_20201117_0838'),
+    ]
+
+    operations = [
+    ]
diff --git a/smash/web/migrations/0180_auto_20201117_0838.py b/smash/web/migrations/0180_auto_20201117_0838.py
new file mode 100644
index 0000000000000000000000000000000000000000..da010905fdfbc27df5f524ddf6c94a6f1106f91c
--- /dev/null
+++ b/smash/web/migrations/0180_auto_20201117_0838.py
@@ -0,0 +1,31 @@
+# Generated by Django 2.0.13 on 2020-11-17 08:38
+
+import django.core.files.storage
+import django.core.validators
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('web', '0179_auto_20201116_1528'),
+    ]
+
+    operations = [
+        migrations.RemoveField(
+            model_name='privacynotice',
+            name='study',
+        ),
+        migrations.AddField(
+            model_name='privacynotice',
+            name='name',
+            field=models.CharField(default='', max_length=255, verbose_name='Name'),
+            preserve_default=False,
+        ),
+        migrations.AlterField(
+            model_name='study',
+            name='study_privacy_notice',
+            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='studies', to='web.PrivacyNotice', verbose_name='Study Privacy Note'),
+        )
+    ]
diff --git a/smash/web/migrations/0180_auto_20201120_1554.py b/smash/web/migrations/0180_auto_20201120_1554.py
new file mode 100644
index 0000000000000000000000000000000000000000..12474a8aebcbd8176fa2562489f2d82d17742dc9
--- /dev/null
+++ b/smash/web/migrations/0180_auto_20201120_1554.py
@@ -0,0 +1,50 @@
+# Generated by Django 2.0.13 on 2020-11-20 15:54
+
+import django.core.files.storage
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('web', '0179_merge_20201117_1048'),
+    ]
+
+    operations = [
+        migrations.AddField(
+            model_name='privacynotice',
+            name='summary',
+            field=models.CharField(default='description', max_length=255, verbose_name='Summary'),
+            preserve_default=False,
+        ),
+        migrations.AddField(
+            model_name='study',
+            name='acceptance_of_study_privacy_notice_required',
+            field=models.BooleanField(default=False, verbose_name='Is privacy notice acceptance required?'),
+        ),
+        migrations.AlterField(
+            model_name='privacynotice',
+            name='created_at',
+            field=models.DateTimeField(auto_now_add=True, verbose_name='Created at'),
+        ),
+        migrations.AlterField(
+            model_name='privacynotice',
+            name='document',
+            field=models.FileField(upload_to='privacy_notices/', verbose_name='Study Privacy Notice file'),
+        ),
+        migrations.AlterField(
+            model_name='privacynotice',
+            name='name',
+            field=models.CharField(max_length=255, verbose_name='Name'),
+        ),
+        migrations.AlterField(
+            model_name='privacynotice',
+            name='updated_at',
+            field=models.DateTimeField(auto_now=True, verbose_name='Updated at'),
+        ),
+        migrations.AlterField(
+            model_name='studysubject',
+            name='referral_letter',
+            field=models.FileField(blank=True, null=True, storage=django.core.files.storage.FileSystemStorage(location='/tmp/upload'), upload_to='referral_letters', verbose_name='Referral letter'),
+        ),
+    ]
diff --git a/smash/web/migrations/0181_worker_privacy_notice_accepted.py b/smash/web/migrations/0181_worker_privacy_notice_accepted.py
new file mode 100644
index 0000000000000000000000000000000000000000..3677558e321d5989c69eaf39163851c6e6fddc47
--- /dev/null
+++ b/smash/web/migrations/0181_worker_privacy_notice_accepted.py
@@ -0,0 +1,18 @@
+# Generated by Django 2.0.13 on 2020-11-20 15:57
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('web', '0180_auto_20201120_1554'),
+    ]
+
+    operations = [
+        migrations.AddField(
+            model_name='worker',
+            name='privacy_notice_accepted',
+            field=models.BooleanField(default=False, verbose_name='Has accepted privacy notice?'),
+        ),
+    ]
diff --git a/smash/web/models/__init__.py b/smash/web/models/__init__.py
index 9c193eaa042b0662683c6f399f21b5053222e89d..46f20636c434b587773fe96e454b017f2248cb14 100644
--- a/smash/web/models/__init__.py
+++ b/smash/web/models/__init__.py
@@ -38,6 +38,7 @@ from .contact_attempt import ContactAttempt
 from .mail_template import MailTemplate
 from .missing_subject import MissingSubject
 from .inconsistent_subject import InconsistentSubject, InconsistentField
+from .privacy_notice import PrivacyNotice
 
 __all__ = [Study, FlyingTeam, Appointment, AppointmentType, Availability, Holiday, Item, Language, Location, Room,
            Subject, StudySubject, StudySubjectList, SubjectColumns, StudyNotificationParameters,
diff --git a/smash/web/models/privacy_notice.py b/smash/web/models/privacy_notice.py
new file mode 100644
index 0000000000000000000000000000000000000000..12c0696145f12c5b569a0595993c69e290532a98
--- /dev/null
+++ b/smash/web/models/privacy_notice.py
@@ -0,0 +1,21 @@
+# coding=utf-8
+import datetime
+
+from django.db import models
+from web.templatetags.filters import basename
+
+class PrivacyNotice(models.Model):
+    name = models.CharField(max_length=255, verbose_name='Name')
+    created_at = models.DateTimeField(auto_now_add=True, verbose_name='Created at')
+    updated_at = models.DateTimeField(auto_now=True, verbose_name='Updated at')
+    summary = models.CharField(max_length=255, verbose_name='Summary', blank=False, null=False)
+    document   = models.FileField(upload_to='privacy_notices/', 
+                                verbose_name='Study Privacy Notice file',
+                                null=False, editable=True)
+
+    def __str__(self):
+        return f'{self.name} ({basename(self.document.url)})'
+
+    @property
+    def all_studies(self):
+        return self.studies.all()
diff --git a/smash/web/models/study.py b/smash/web/models/study.py
index 41006b1e335c42c217a35b925ed5b2db454ae741..83f438ebaa452e7a5ca9ae442b5ccb45b8d65b3e 100644
--- a/smash/web/models/study.py
+++ b/smash/web/models/study.py
@@ -94,6 +94,18 @@ class Study(models.Model):
                                                               blank=False
                                                               )
 
+    study_privacy_notice = models.ForeignKey("web.PrivacyNotice",
+                              verbose_name='Study Privacy Note',
+                              editable=True, blank=True,
+                              null=True, on_delete=models.SET_NULL,
+                              related_name='studies'
+                              )
+
+    acceptance_of_study_privacy_notice_required = models.BooleanField(
+        default=False,
+        verbose_name="Is privacy notice acceptance required?"
+    )
+
     def check_nd_number(self, nd_number):
         regex = re.compile(self.nd_number_study_subject_regex)
         return regex.match(nd_number) is not None
diff --git a/smash/web/models/worker.py b/smash/web/models/worker.py
index 83793ffd80514f25d2df2950b0caa38a6ce95caa..8de5a4258bacc945bcd73fb346c9b5cab0e8ed8f 100644
--- a/smash/web/models/worker.py
+++ b/smash/web/models/worker.py
@@ -154,6 +154,10 @@ class Worker(models.Model):
                                blank=True
                                )
 
+    privacy_notice_accepted = models.BooleanField(
+        default=False,
+        verbose_name="Has accepted privacy notice?")
+
     def is_on_leave(self):
         if len(self.holiday_set.filter(datetime_end__gt=timezone.now(),
                                        datetime_start__lt=timezone.now(),
diff --git a/smash/web/templates/_base.html b/smash/web/templates/_base.html
index b5ec2ee0002e84a2b0fdf164914f2742f5e1e8ea..688db99e33a405591cbaeaad32c84fca14fbd5bf 100644
--- a/smash/web/templates/_base.html
+++ b/smash/web/templates/_base.html
@@ -32,6 +32,8 @@
         <script src="https://oss.maxcdn.com/html5shiv/3.7.3/html5shiv.min.js"></script>
         <script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
         <![endif]-->
+        <script src="https://cdn.jsdelivr.net/npm/cookieconsent@3/build/cookieconsent.min.js"></script>
+        <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/cookieconsent@3/build/cookieconsent.min.css">
     {% endblock styles %}
 </head>
 <!--
@@ -73,7 +75,7 @@ desired effect
             <a href="#" class="sidebar-toggle" data-toggle="offcanvas" role="button">
                 <span class="sr-only">Toggle navigation</span>
             </a>
-            
+
               <div class="col-xs-7 navbar-text" style="margin-left: 0px">
                 <div class="warning_ticker">
                   <div class="ticker_list">
@@ -388,7 +390,7 @@ desired effect
               mousePause: 1
             });
         }else if($('.ticker_list').children().length == 1){
-          
+
         }else{
           $('.warning_ticker').css('display', 'none');
         }
@@ -397,12 +399,42 @@ desired effect
             var $e = $(".sidebar-menu li[data-desc='" + page_to_activate + "']");
             $e.addClass("active");
             if($($e).parents('li[data-desc]').length > 0){ //if there is a parent, it should also be active
-              $($e).parents('li[data-desc]').addClass("active");  
+              $($e).parents('li[data-desc]').addClass("active");
             }
-            
+
         };
 
         activate({% block ui_active_tab %}{% endblock ui_active_tab %});
+        if ("{{ show_notice }}".toLowerCase() === "true") {
+            window.cookieconsent.initialise({
+                container: document.getElementById("content"),
+                content: {
+                    header: 'Privacy notice!',
+                    message: '{{ study.study_privacy_notice.summary}}',
+                    href: '{{ study.study_privacy_notice.document.url }}',
+                    dismiss: 'Got it!',
+                },
+                palette: {
+                    popup: {background: "#fff"},
+                    button: {background: "#aa0000"},
+                },
+                revokable: true,
+                onStatusChange: function (status) {
+                    if (this.hasConsented()) {
+                        $.ajax({
+                            url: "{% url 'web.api.workers.accept_privacy_notice' %}",
+                            success: function (result) {
+                                if (result.isOk === false) console.log(result.message);
+                            },
+                            async: false
+                        });
+                    }
+                },
+                law: {
+                    regionalLaw: false,
+                }
+            });
+        }
     </script>
 
     {% comment "TODO: Check, and add if works %}
diff --git a/smash/web/templates/privacy_notice/acceptance_study_privacy_notice.html b/smash/web/templates/privacy_notice/acceptance_study_privacy_notice.html
new file mode 100644
index 0000000000000000000000000000000000000000..e2c1a1d6f58e1c446e3727aff344427f72b53773
--- /dev/null
+++ b/smash/web/templates/privacy_notice/acceptance_study_privacy_notice.html
@@ -0,0 +1,62 @@
+{% extends "_base.html" %}
+{% load static %}
+{% load filters %}
+
+{% block styles %}
+    {{ block.super }}
+{% endblock styles %}
+
+{% block ui_active_tab %}'workers'{% endblock ui_active_tab %}
+{% block page_description %}{% endblock page_description %}
+
+{% block maincontent %}
+
+    {% block content %}
+        <div class="row">
+            <div class="col-md-12">
+                <div class="box box-success">
+                    <div class="box-header with-border">
+                        <h3 class="box-title">{% block form-title %}Check the privacy notice{% endblock %}</h3>
+                    </div>
+
+
+                    <form method="post" action="" class="form-horizontal" enctype="multipart/form-data">
+                        {% csrf_token %}
+
+                        <div class="box-body">
+                            <div class="form-group {% if field.errors %}has-error{% endif %}">
+                                <label class="col-sm-4  col-lg-offset-1 col-lg-2 control-label">
+                                    <p >{{privacy_notice.summary}}. Read <a href="{{ privacy_notice.document.url }}">more</a></p>
+                                </label>
+                            </div>
+                        </div><!-- /.box-body -->
+                        <div class="box-footer">
+                            <div class="col-sm-6">
+                                <a class="btn btn-block btn-info" href="{% url 'logout' %}">
+                                    I do not agree
+                                </a>
+                            </div>
+                            <div class="col-sm-6">
+                                <button type="submit" class="btn btn-block btn-success">{% block save-button %}
+                                    I agree{% endblock %}</button>
+                            </div>
+                        </div><!-- /.box-footer -->
+                    </form>
+                </div>
+
+            </div>
+        </div>
+
+    {% endblock %}
+
+
+{% endblock maincontent %}
+
+{% block scripts %}
+    {{ block.super }}
+
+    <script type="text/javascript">
+
+        
+    </script>
+{% endblock scripts %}
\ No newline at end of file
diff --git a/smash/web/templates/privacy_notice/add.html b/smash/web/templates/privacy_notice/add.html
new file mode 100644
index 0000000000000000000000000000000000000000..6d4f87bf936db78ad7926b81338120374ef97eca
--- /dev/null
+++ b/smash/web/templates/privacy_notice/add.html
@@ -0,0 +1,8 @@
+{% extends "privacy_notice/add_edit.html" %}
+
+{% block page_header %}New privacy notice{% endblock page_header %}
+
+{% block title %}{{ block.super }} - Add new privacy notice{% endblock %}
+
+{% block form-title %}Enter privacy notice details{% endblock %}
+{% block save-button %}Add{% endblock %}
\ No newline at end of file
diff --git a/smash/web/templates/privacy_notice/add_edit.html b/smash/web/templates/privacy_notice/add_edit.html
new file mode 100644
index 0000000000000000000000000000000000000000..17ad93d68448db002bc8e4c813749e38dacabfce
--- /dev/null
+++ b/smash/web/templates/privacy_notice/add_edit.html
@@ -0,0 +1,83 @@
+{% extends "_base.html" %}
+{% load static %}
+{% load filters %}
+
+{% block styles %}
+    {{ block.super }}
+    <link rel="stylesheet" href="{% static 'AdminLTE/plugins/awesomplete/awesomplete.css' %}"/>
+    <style type="text/css">
+        .help_text{
+            margin-left: 5px;
+        }
+    </style>
+{% endblock styles %}
+
+{% block ui_active_tab %}'subjects'{% endblock ui_active_tab %}
+{% block page_description %}{% endblock page_description %}
+
+{% block breadcrumb %}
+    {% include "privacy_notice/breadcrumb.html" %}
+{% endblock breadcrumb %}
+
+{% block maincontent %}
+
+    {% block content %}
+        <div class="row">
+            <div class="col-md-12">
+                <div class="box box-success">
+                    <div class="box-header with-border">
+                        <h3 class="box-title">{% block form-title %}Enter privacy notice details{% endblock %}</h3>
+                    </div>
+
+
+                    <form method="post" action="" class="form-horizontal" enctype="multipart/form-data">
+                        {% csrf_token %}
+
+                        <div class="box-body">
+                            {% for field in form %}
+                                <div class="form-group {% if field.errors %}has-error{% endif %}">
+                                    <label class="col-sm-4  col-lg-offset-1 col-lg-2 control-label">
+                                        {{ field.label }}
+                                        {% if field.help_text %}
+                                           <i class="fa fa-info-circle help_text" aria-hidden="true" data-toggle="tooltip" data-placement="top" title="{{field.help_text}}"></i>
+                                        {% endif %}
+                                    </label>
+
+                                    <div class="col-sm-8 col-lg-4">
+                                        {{ field|add_class:'form-control' }}
+                                        {% if field.errors %}
+                                            <span class="help-block">{{ field.errors }}</span>
+                                        {% endif %}
+                                    </div>
+
+
+                                </div>
+                            {% endfor %}
+                        </div><!-- /.box-body -->
+                        <div class="box-footer">
+                            <div class="col-sm-6">
+                                <button type="submit" class="btn btn-block btn-success">{% block save-button %}
+                                    Add{% endblock %}</button>
+                            </div>
+                            <div class="col-sm-6">
+                                <a href="{% url 'web.views.privacy_notices' %}"
+                                   class="btn btn-block btn-default">Cancel</a>
+                            </div>
+                        </div><!-- /.box-footer -->
+                    </form>
+                </div>
+
+            </div>
+        </div>
+
+    {% endblock %}
+
+
+{% endblock maincontent %}
+
+{% block scripts %}
+    {{ block.super }}
+
+    <script src="{% static 'AdminLTE/plugins/awesomplete/awesomplete.min.js' %}"></script>
+    
+{% endblock scripts %}
\ No newline at end of file
diff --git a/smash/web/templates/privacy_notice/breadcrumb.html b/smash/web/templates/privacy_notice/breadcrumb.html
new file mode 100644
index 0000000000000000000000000000000000000000..3a3bdd23e7829eec33bf65d789fd90b566940f2b
--- /dev/null
+++ b/smash/web/templates/privacy_notice/breadcrumb.html
@@ -0,0 +1,2 @@
+<li><a href="{% url 'web.views.appointments' %}"><i class="fa fa-dashboard"></i> Dashboard</a></li>
+<li class="active"><a href="{% url 'web.views.privacy_notices' %}">Privacy Notices</a></li>
\ No newline at end of file
diff --git a/smash/web/templates/privacy_notice/confirm_delete.html b/smash/web/templates/privacy_notice/confirm_delete.html
new file mode 100644
index 0000000000000000000000000000000000000000..8e618e11025dea0fff578d6dca8546038dadf85f
--- /dev/null
+++ b/smash/web/templates/privacy_notice/confirm_delete.html
@@ -0,0 +1,62 @@
+{% extends "_base.html" %}
+{% load static %}
+{% load filters %}
+
+{% block styles %}
+    {{ block.super }}
+    <link rel="stylesheet" href="{% static 'AdminLTE/plugins/awesomplete/awesomplete.css' %}"/>
+
+{% endblock styles %}
+
+{% block ui_active_tab %}'subjects'{% endblock ui_active_tab %}
+{% block page_header %}Delete privacy notice{% endblock page_header %}
+{% block page_description %}{% endblock page_description %}
+
+{% block title %}{{ block.super }} - Delete privacy notice{% endblock %}
+
+{% block breadcrumb %}
+    {% include "privacy_notice/breadcrumb.html" %}
+{% endblock breadcrumb %}
+
+{% block maincontent %}
+
+    {% block content %}
+        <div class="row">
+            <div class="col-md-12">
+                <div class="box box-success">
+                    <div class="box-header with-border">
+                        <h3 class="box-title">Confirm deletion</h3>
+                    </div>
+
+                    <form action="" method="post" class="form-horizontal">{% csrf_token %}
+                        <div class="box-body">
+                            <p>Are you sure you want to delete privacy notice "{{ object.document.url | basename }}" from Study "{{object.study}}"?</p>
+                        </div><!-- /.box-body -->
+                        <div class="box-footer">
+                            <div class="col-sm-6">
+                                <button type="submit" class="btn btn-block btn-danger">Delete</button>
+                            </div>
+                            <div class="col-sm-6">
+                                <a href="{% url 'web.views.privacy_notices' %}"
+                                   class="btn btn-block btn-default">Cancel</a>
+                            </div>
+                        </div><!-- /.box-footer -->
+                    </form>
+                </div>
+
+            </div>
+        </div>
+
+    {% endblock %}
+
+
+{% endblock maincontent %}
+
+{% block scripts %}
+    {{ block.super }}
+
+    <script src="{% static 'AdminLTE/plugins/awesomplete/awesomplete.min.js' %}"></script>
+
+{% endblock scripts %}
+
+
diff --git a/smash/web/templates/privacy_notice/edit.html b/smash/web/templates/privacy_notice/edit.html
new file mode 100644
index 0000000000000000000000000000000000000000..f1f0d651f3d94b4c6f27a7fcea64d0d4f86dcaf1
--- /dev/null
+++ b/smash/web/templates/privacy_notice/edit.html
@@ -0,0 +1,9 @@
+{% extends "privacy_notice/add_edit.html" %}
+
+{% block page_header %}Edit privacy notice "{{ privacy_notice.name }}"{% endblock page_header %}
+
+{% block title %}{{ block.super }} - Edit privacy notice "{{ privacy_notice.name }}"{% endblock %}
+
+{% block form-title %}Enter privacy notice details{% endblock %}
+
+{% block save-button %}Save{% endblock %}
diff --git a/smash/web/templates/privacy_notice/list.html b/smash/web/templates/privacy_notice/list.html
new file mode 100644
index 0000000000000000000000000000000000000000..f9a4ebe47515723a05a3d2082301265e6bbf9121
--- /dev/null
+++ b/smash/web/templates/privacy_notice/list.html
@@ -0,0 +1,92 @@
+{% extends "_base.html" %}
+{% load static %}
+{% load filters %}
+
+{% block styles %}
+    {{ block.super }}
+    <!-- DataTables -->
+    <link rel="stylesheet" href="{% static 'AdminLTE/plugins/datatables/dataTables.bootstrap.css' %}">
+{% endblock styles %}
+
+{% block ui_active_tab %}'privacy_notices'{% endblock ui_active_tab %}
+{% block page_header %}Privacy Notices{% endblock page_header %}
+{% block page_description %}{% endblock page_description %}
+
+{% block breadcrumb %}
+    {% include "privacy_notice/breadcrumb.html" %}
+{% endblock breadcrumb %}
+
+{% block maincontent %}
+
+
+    <div class="box box-success">
+        <div class="box-header with-border">
+            <h3 class="box-title">Privacy Notices</h3>
+        </div>
+        <div class="box-body">
+
+            <div>
+                <a class="btn btn-app" href="{% url 'web.views.privacy_notice_add' %}">
+                    <i class="fa fa-plus"></i> Add new privacy notice
+                </a>
+            </div>
+            <table id="table" class="table table-bordered table-striped">
+                <thead>
+                <tr>
+                    <th>No.</th>
+                    <th>Name</th>
+                    <th>Studies</th>
+                    <th>Creation Date</th>
+                    <th>Last Updated</th>
+                    <th>Download</th>
+                    <th>Edit</th>
+                    <th>Delete</th>
+                </tr>
+                </thead>
+                <tbody>
+                {% for privacy_notice in privacy_notices %}
+                    <tr>
+                        <td>{{ forloop.counter }}</td>
+                        <td>{{ privacy_notice.name }}</td>
+                        <td>
+                            <ul>
+                                {% for study in privacy_notice.all_studies %}
+                                <li>{{ study }}</li>
+                                {% endfor %}
+                            </ul>
+                        </td>
+                        <td>{{ privacy_notice.created_at }}</td>
+                        <td>{{ privacy_notice.updated_at }}</td>
+                        <td><a href="{{ privacy_notice.document.url }}"><i class="fa fa-download"></i></a>&nbsp; &nbsp;{{privacy_notice.document.url | basename}}</td>
+                        <td><a href="{% url 'web.views.privacy_notice_edit' privacy_notice.id %}"><i
+                                class="fa fa-edit"></i></a></td>
+                        <td><a href="{% url 'web.views.privacy_notice_delete' privacy_notice.id %}"><i
+                                class="fa fa-trash text-danger"></i></a></td>
+                    </tr>
+                {% endfor %}
+                </tbody>
+            </table>
+        </div>
+    </div>
+
+{% endblock maincontent %}
+
+{% block scripts %}
+    {{ block.super }}
+
+    <script src="{% static 'AdminLTE/plugins/datatables/jquery.dataTables.min.js' %}"></script>
+    <script src="{% static 'AdminLTE/plugins/datatables/dataTables.bootstrap.min.js' %}"></script>
+
+    <script>
+        $(function () {
+            $('#table').DataTable({
+                "paging": true,
+                "lengthChange": false,
+                "searching": true,
+                "ordering": true,
+                "info": true,
+                "autoWidth": false
+            });
+        });
+    </script>
+{% endblock scripts %}
diff --git a/smash/web/templates/study/edit.html b/smash/web/templates/study/edit.html
index 5808f33837a87adc20dda1b7ec7f9ca0d9591a0a..ef795d8879bb28bd13c90457bc743c9c00ca4b0c 100644
--- a/smash/web/templates/study/edit.html
+++ b/smash/web/templates/study/edit.html
@@ -6,14 +6,19 @@
     {{ block.super }}
     <!-- DataTables -->
     <link rel="stylesheet" href="{% static 'AdminLTE/plugins/datatables/dataTables.bootstrap.css' %}">
+    {% include "includes/datepicker.css.html" %}
+    {% include "includes/datetimepicker.css.html" %}
     <style type="text/css">
         .tooltip-inner {
-            max-width: 350px;
-            width: 350px;
+            max-width: 200px;
+            width: 200px; 
+        }
+        .privacy-notice-buttons {
+            float: right;
+            padding: 0;
+            margin-top: 7px;
         }
     </style>
-    {% include "includes/datepicker.css.html" %}
-    {% include "includes/datetimepicker.css.html" %}
 {% endblock styles %}
 
 {% block ui_active_tab %}'study_conf'{% endblock ui_active_tab %}
@@ -55,10 +60,29 @@
                                                    data-placement="bottom" title="{{ field.help_text }}"></i>
                                             {% endif %}
                                         </label>
-
-                                        <div class="col-sm-8">
-                                            {{ field|add_class:'form-control' }}
-                                        </div>
+                                        
+                                        {% if field.label == 'Study Privacy Note' %} 
+                                            <div class="col-sm-7">
+                                                {{ field|add_class:'form-control' }}
+                                            </div>
+                                            <div class="col-sm-1 privacy-notice-buttons">
+                                                {% if privacy_notice %}
+                                                <a title="Edit selected privacy notice" href="{% url 'web.views.privacy_notice_edit' field.value %}">
+                                                    <i class="fa fa-edit"></i>
+                                                </a>
+                                                <a title="Download selected privacy notice" href="{{ privacy_notice.document.url }}">
+                                                    <i class="fa fa-download"></i>
+                                                </a>
+                                                {% endif %}
+                                                <a title="Add privacy notice" href="{% url 'web.views.privacy_notice_add' %}">
+                                                    <i class="fa fa-plus"></i> 
+                                                </a>
+                                            </div>
+                                        {% else %}
+                                            <div class="col-sm-8">
+                                                {{ field|add_class:'form-control' }}
+                                            </div>
+                                        {% endif %}
 
                                         {% if field.errors %}
                                             <span class="help-block"> {{ field.errors }} </span>
@@ -178,4 +202,10 @@
 
     {% include "includes/datepicker.js.html" %}
     {% include "includes/datetimepicker.js.html" %}
+
+    <script>
+        $(function(){
+            $('a[title]').tooltip({container: 'body'})
+        })
+    </script>
 {% endblock scripts %}
diff --git a/smash/web/templatetags/filters.py b/smash/web/templatetags/filters.py
index a7a63383cf825187fbac57307b97da48f68a0da0..6e2e122ef8c1ea1bc89c060ff220de717fc720be 100644
--- a/smash/web/templatetags/filters.py
+++ b/smash/web/templatetags/filters.py
@@ -2,7 +2,7 @@
 from django import template
 from django.forms import CheckboxSelectMultiple, CheckboxInput
 from django.utils.safestring import mark_safe
-import datetime
+import datetime, os
 from web.models import ConfigurationItem
 from web.models.constants import VISIT_SHOW_VISIT_NUMBER_FROM_ZERO
 from distutils.util import strtobool
@@ -59,4 +59,8 @@ def display_visit_number(visit_number):
     if strtobool(visit_from_zero):
         return (visit_number - 1)
     else:
-        return visit_number
\ No newline at end of file
+        return visit_number
+
+@register.filter(name='basename')
+def basename(path):
+    return os.path.basename(path)
\ No newline at end of file
diff --git a/smash/web/tests/view/test_privacy_notice.py b/smash/web/tests/view/test_privacy_notice.py
new file mode 100644
index 0000000000000000000000000000000000000000..609d46b55efc863445b80abf758a195bb08642aa
--- /dev/null
+++ b/smash/web/tests/view/test_privacy_notice.py
@@ -0,0 +1,126 @@
+from web.tests.functions import get_resource_path, get_test_study
+from web.models import PrivacyNotice, Study, Worker
+from web.forms import PrivacyNoticeForm, WorkerAcceptPrivacyNoticeForm
+from web.tests import LoggedInTestCase
+from django.urls import reverse
+from django.core.files.uploadedfile import SimpleUploadedFile
+from django.contrib.messages import get_messages
+from web.models.constants import GLOBAL_STUDY_ID
+
+class PrivacyNoticeTests(LoggedInTestCase):
+    def test_add_privacy_notice(self):
+        self.assertEqual(0, PrivacyNotice.objects.count())
+        self.login_as_admin()
+
+        form_data = dict(
+            name='example', 
+            summary='example summary'
+        )
+
+        file_data = dict(
+            document=SimpleUploadedFile('file.txt', b"file_content")
+        )
+
+        form = PrivacyNoticeForm(form_data, file_data)
+        self.assertTrue(form.is_valid())
+
+        page = reverse('web.views.privacy_notice_add')
+        response = self.client.post(page, data={**form_data, **file_data})
+        self.assertEqual(response.status_code, 302)
+        self.assertEqual(1, PrivacyNotice.objects.count())
+
+    def test_edit_privacy_notice(self):
+        self.test_add_privacy_notice()
+        self.assertEqual(1, PrivacyNotice.objects.count())
+        pn = PrivacyNotice.objects.all()[0]
+        form_data = dict(
+            name='example2',
+            summary=pn.summary
+        )
+
+        file_data = dict(
+            document=SimpleUploadedFile('file.txt', b"file_content")
+        )
+
+        form = PrivacyNoticeForm(form_data, file_data, instance=pn)
+        self.assertTrue(form.is_valid())
+
+        page = reverse('web.views.privacy_notice_edit', kwargs={'pk': pn.id})
+        response = self.client.post(page, data={**form_data, **file_data})
+        self.assertEqual(response.status_code, 302)
+        pn = PrivacyNotice.objects.all()[0]
+        self.assertEqual(pn.name, 'example2')
+
+    def test_delete_privacy_notice(self):
+        self.test_add_privacy_notice()
+        self.assertEqual(1, PrivacyNotice.objects.count())
+        pn = PrivacyNotice.objects.all()[0]
+        page = reverse('web.views.privacy_notice_delete', kwargs={'pk': pn.id})
+        response = self.client.post(page)
+        self.assertEqual(response.status_code, 302)
+        self.assertEqual(0, PrivacyNotice.objects.count())
+        
+    def test_privacy_notice_middleware_superuser(self):
+        self.test_add_privacy_notice()
+        
+        self.login_as_admin()
+        #assign privacy notice
+        pn = PrivacyNotice.objects.all()[0]
+        study = Study.objects.filter(id=GLOBAL_STUDY_ID)[0]
+        study.acceptance_of_study_privacy_notice_required = True
+        study.study_privacy_notice = pn
+        study.save()
+
+        study = Study.objects.filter(id=GLOBAL_STUDY_ID)[0]
+        self.assertEqual(study.acceptance_of_study_privacy_notice_required, True)
+        self.assertEqual(study.study_privacy_notice.id, pn.id)
+
+        self.login_as_super()
+        self.assertEqual(self.staff_worker.privacy_notice_accepted, False)
+        page = reverse('web.views.appointments')
+        response = self.client.get(page)
+        self.assertEqual(response.status_code, 200)
+        messages = list(get_messages(response.wsgi_request))
+        self.assertEqual(len(messages), 0)
+    
+    def test_privacy_notice_middleware(self):
+        self.test_add_privacy_notice()
+        
+        self.login_as_admin()
+        #assign privacy notice
+        pn = PrivacyNotice.objects.all()[0]
+        study = Study.objects.filter(id=GLOBAL_STUDY_ID)[0]
+        study.acceptance_of_study_privacy_notice_required = True
+        study.study_privacy_notice = pn
+        study.save()
+
+        study = Study.objects.filter(id=GLOBAL_STUDY_ID)[0]
+        self.assertEqual(study.acceptance_of_study_privacy_notice_required, True)
+        self.assertEqual(study.study_privacy_notice.id, pn.id)
+
+        self.login_as_staff()
+        self.assertEqual(self.staff_worker.privacy_notice_accepted, False)
+        page = reverse('web.views.appointments')
+        response = self.client.get(page)
+        self.assertEqual(response.status_code, 302)
+        messages = list(get_messages(response.wsgi_request))
+        self.assertEqual(len(messages), 1)
+        self.assertEqual(str(messages[0]), "You can't use the system until you accept the privacy notice.")
+        #accept privacy notice
+        form_data = dict(privacy_notice_accepted=True)
+        form = WorkerAcceptPrivacyNoticeForm(form_data)
+        self.assertTrue(form.is_valid())
+        page = reverse('web.views.accept_privacy_notice', kwargs={'pk': pn.id})
+        response = self.client.post(page, data={**form_data})
+        self.assertEqual(response.status_code, 302)
+        messages = [m.message for m in get_messages(response.wsgi_request)]
+        self.assertIn("Privacy notice accepted", messages)
+        #check acceptance
+        worker = Worker.objects.filter(id=self.staff_worker.id).first()
+        self.assertEqual(worker.privacy_notice_accepted, True)
+        page = reverse('web.views.appointments')
+        response = self.client.get(page)
+        self.assertEqual(response.status_code, 200)
+        messages = list(get_messages(response.wsgi_request))
+        worker = Worker.get_by_user(response.wsgi_request.user)
+        self.assertEqual(worker.privacy_notice_accepted, True)
diff --git a/smash/web/urls.py b/smash/web/urls.py
index ce04e3b0b6fbcbf1101339161785ebafa384b049..1b76de8eaf3b42f2ce08b31e57164ea92cc0dd83 100644
--- a/smash/web/urls.py
+++ b/smash/web/urls.py
@@ -169,6 +169,19 @@ urlpatterns = [
     url(r'^equipment_and_rooms/rooms/delete/(?P<room_id>\d+)$', views.rooms.rooms_delete,
         name='web.views.equipment_and_rooms.rooms_delete'),
 
+    ####################
+    #  PRIVACY NOTICE  #
+    ####################
+
+    url(r'^privacy_notices$', views.privacy_notice.PrivacyNoticeListView.as_view(), name='web.views.privacy_notices'),
+    
+    url(r'^accept_privacy_notice/(?P<pk>\d+)$', views.privacy_notice.privacy_notice_accept, name='web.views.accept_privacy_notice'),
+
+    url(r'^privacy_notices/add$', views.privacy_notice.privacy_notice_add, name='web.views.privacy_notice_add'),
+    url(r'^privacy_notices/(?P<pk>\d+)/edit$', views.privacy_notice.privacy_notice_edit, name='web.views.privacy_notice_edit'),
+
+    url(r'^privacy_notices/(?P<pk>\d+)/delete$', views.privacy_notice.PrivacyNoticeDeleteView.as_view(), name='web.views.privacy_notice_delete'),
+   
     ####################
     #       MAIL       #
     ####################
diff --git a/smash/web/views/__init__.py b/smash/web/views/__init__.py
index 90f254227fb955480ca1425d8a6a4764dd004ca6..779ba85535665619709884c836ee7480316f1aea 100644
--- a/smash/web/views/__init__.py
+++ b/smash/web/views/__init__.py
@@ -1,5 +1,6 @@
 # coding=utf-8
 from django.conf import settings
+from django.http import HttpRequest
 from django.shortcuts import redirect, render
 from django.views.generic.base import ContextMixin
 
@@ -41,13 +42,16 @@ def wrap_response(request, template, params):
     return render(request, template, final_params)
 
 
-def extend_context(params, request):
+def extend_context(params, request: HttpRequest):
     study = Study.get_by_id(GLOBAL_STUDY_ID)
     person = Worker.get_by_user(request.user) # None if AnonymousUser or no Worker associated
     permissions = set()
+    show_notice = True
     if person is not None:
         role = person.role
         permissions = person.get_permissions(study)
+        show_notice = study.study_privacy_notice \
+                      and not person.privacy_notice_accepted
         person = str(person)
     else:
         #use full name if available, username otherwise
@@ -56,6 +60,8 @@ def extend_context(params, request):
         else:
             person = request.user.get_username()
         role   = '<No worker information>'
+    if request.resolver_match is not None and request.resolver_match.url_name == 'web.views.accept_privacy_notice':
+        show_notice = False
     notifications = get_notifications(request.user)
     final_params = params.copy()
     final_params.update({
@@ -65,6 +71,7 @@ def extend_context(params, request):
         'person': person,
         'role': role,
         'notifications': notifications,
+        'show_notice' : show_notice,
         'study_id': GLOBAL_STUDY_ID,
         'study' : study
     })
@@ -105,4 +112,5 @@ from . import uploaded_files
 from . import study
 from . import password
 from . import appointment_type
-from . import provenance
\ No newline at end of file
+from . import provenance
+from . import privacy_notice
\ No newline at end of file
diff --git a/smash/web/views/privacy_notice.py b/smash/web/views/privacy_notice.py
new file mode 100644
index 0000000000000000000000000000000000000000..dc44ade1a75b40d399528b4d13bedff39e38125c
--- /dev/null
+++ b/smash/web/views/privacy_notice.py
@@ -0,0 +1,108 @@
+# coding=utf-8
+import io
+from wsgiref.util import FileWrapper
+
+from django.contrib import messages
+from django.http import HttpResponse
+from django.shortcuts import redirect, get_object_or_404
+from django.urls import reverse_lazy
+from django.views.generic import DeleteView
+from django.views.generic import ListView
+
+from web.decorators import PermissionDecorator
+from . import WrappedView
+from . import wrap_response
+from ..forms.privacy_notice import PrivacyNoticeForm
+from ..forms.worker_form import WorkerAcceptPrivacyNoticeForm
+from ..models import PrivacyNotice, Worker
+
+
+class PrivacyNoticeListView(ListView, WrappedView):
+    model = PrivacyNotice
+    context_object_name = "privacy_notices"
+    template_name = 'privacy_notice/list.html'
+
+    @PermissionDecorator('change_privacynotice', 'privacynotice')
+    def dispatch(self, *args, **kwargs):
+        return super(PrivacyNoticeListView, self).dispatch(*args, **kwargs)
+
+
+@PermissionDecorator('change_privacynotice', 'privacynotice')
+def privacy_notice_add(request):
+    if request.method == 'POST':
+        form = PrivacyNoticeForm(request.POST, request.FILES)
+        if form.is_valid():
+            try:
+                form.save()
+            except:
+                messages.add_message(request, messages.ERROR, 'There was a problem when saving privacy notice. '
+                                                              'Contact system administrator.')
+            return redirect('web.views.privacy_notices')
+    else:
+        form = PrivacyNoticeForm()
+
+    return wrap_response(request, 'privacy_notice/add.html', {'form': form})
+
+
+@PermissionDecorator('change_privacynotice', 'privacynotice')
+def privacy_notice_edit(request, pk):
+    privacy_notice = get_object_or_404(PrivacyNotice, pk=pk)
+    if request.method == 'POST':
+        form = PrivacyNoticeForm(request.POST, request.FILES, instance=privacy_notice)
+        if form.is_valid():
+            try:
+                form.save()
+                return redirect('web.views.privacy_notices')
+            except:
+                messages.add_message(request, messages.ERROR, 'There was a problem when updating the privacy notice.'
+                                                              'Contact system administrator.')
+                return wrap_response(request, 'privacy_notice/edit.html',
+                                     {'form': form, 'privacy_notice': privacy_notice})
+    else:
+        form = PrivacyNoticeForm(instance=privacy_notice)
+
+    return wrap_response(request, 'privacy_notice/edit.html', {'form': form, 'privacy_notice': privacy_notice})
+
+
+class PrivacyNoticeDeleteView(DeleteView, WrappedView):
+    model = PrivacyNotice
+    success_url = reverse_lazy('web.views.privacy_notices')
+    template_name = 'privacy_notice/confirm_delete.html'
+
+    @PermissionDecorator('change_privacynotice', 'privacynotice')
+    def delete(self, request, *args, **kwargs):
+        messages.success(request, "Privacy Notice deleted")
+        # try:
+        return super(PrivacyNoticeDeleteView, self).delete(request, *args, **kwargs)
+        # except:
+        #    messages.add_message(request, messages.ERROR, 'There was a problem when deleting privacy notice. '
+        #                                                  'Contact system administrator.')
+        return redirect('web.views.privacy_notices')
+
+
+def privacy_notice_accept(request, pk):
+    privacy_notice = get_object_or_404(PrivacyNotice, pk=pk)
+    worker = Worker.get_by_user(request.user)
+    if request.method == 'POST':
+        form = WorkerAcceptPrivacyNoticeForm(request.POST, instance=worker)
+        if form.is_valid():
+            # noinspection PyBroadException
+            try:
+                form.save()
+                if form.cleaned_data['privacy_notice_accepted']:
+                    messages.add_message(request, messages.SUCCESS, 'Privacy notice accepted')
+                    if request.POST.get('next'):
+                        return redirect(request.POST.get('next'))
+                    return redirect('web.views.appointments')
+                else:
+                    return redirect('logout')
+            except BaseException:
+                messages.add_message(request, messages.ERROR, 'There was a problem when updating the privacy notice.'
+                                                              'Contact system administrator.')
+                return wrap_response(request, 'privacy_notice/acceptance_study_privacy_notice.html',
+                                     {'form': form, 'privacy_notice': privacy_notice})
+    else:
+        form = WorkerAcceptPrivacyNoticeForm(instance=worker)
+
+    return wrap_response(request, 'privacy_notice/acceptance_study_privacy_notice.html',
+                         {'form': form, 'privacy_notice': privacy_notice})
diff --git a/smash/web/views/study.py b/smash/web/views/study.py
index 8d8bc07de6ef171d55ed5b4a21065e5af95bca72..7060a98284ba20e9b8f99b9795c0a31591d2311f 100644
--- a/smash/web/views/study.py
+++ b/smash/web/views/study.py
@@ -53,6 +53,7 @@ def study_edit(request, study_id):
 
     return wrap_response(request, 'study/edit.html', {
         'study_form': study_form,
+        'privacy_notice': study.study_privacy_notice,
         'notifications_form': notifications_form,
         'study_columns_form': study_columns_form,
         'redcap_columns_form': redcap_columns_form