Update the assignment form with feedback from Pam/Denver.
This commit is contained in:
parent
2b1fd9ab90
commit
0565f9b308
11 changed files with 404 additions and 90 deletions
10
requirements.txt
Normal file
10
requirements.txt
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
backports.functools-lru-cache==1.6.4
|
||||||
|
beautifulsoup4==4.9.3
|
||||||
|
bs4==0.0.1
|
||||||
|
Django==1.11.29
|
||||||
|
pytz==2021.3
|
||||||
|
soupsieve==1.9.6
|
||||||
|
html5lib==0.999999999
|
||||||
|
future
|
||||||
|
|
||||||
|
django_countries==5.5 # Supports both Python 2 and 3.
|
59
www/conservancy/apps/assignment/forms.py
Normal file
59
www/conservancy/apps/assignment/forms.py
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
from django import forms
|
||||||
|
from django.core.validators import ValidationError
|
||||||
|
from django.utils import timezone
|
||||||
|
|
||||||
|
from .models import Assignment
|
||||||
|
from .terms import TERMS
|
||||||
|
|
||||||
|
|
||||||
|
def validate_in_past(value):
|
||||||
|
if value >= timezone.now().date():
|
||||||
|
raise ValidationError('Enter a date in the past')
|
||||||
|
|
||||||
|
|
||||||
|
class AssignmentForm(forms.ModelForm):
|
||||||
|
period_begins = forms.DateField(
|
||||||
|
label='Start of period to assign',
|
||||||
|
required=True,
|
||||||
|
widget=forms.DateInput(attrs={'type': 'date'}),
|
||||||
|
validators=[validate_in_past],
|
||||||
|
)
|
||||||
|
period_end_type = forms.ChoiceField(
|
||||||
|
label='End of period to assign',
|
||||||
|
choices=[
|
||||||
|
('all future contributions', 'all future contributions'),
|
||||||
|
('a specific past date', 'a specific past date (specify below)'),
|
||||||
|
],
|
||||||
|
widget=forms.RadioSelect(),
|
||||||
|
)
|
||||||
|
period_ends = forms.DateField(
|
||||||
|
label='Specific past date (if applicable)',
|
||||||
|
required=False,
|
||||||
|
widget=forms.DateInput(attrs={'type': 'date'}),
|
||||||
|
validators=[validate_in_past],
|
||||||
|
)
|
||||||
|
agreement_terms = forms.CharField(
|
||||||
|
widget=forms.Textarea(attrs={'readonly': 'readonly'}),
|
||||||
|
initial=TERMS,
|
||||||
|
help_text='Please be aware that some employment agreements explicitly transfer copyright ownership to the employer. We recommend you review your recent employment agreements for such clauses.',
|
||||||
|
)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = Assignment
|
||||||
|
fields = [
|
||||||
|
'full_name',
|
||||||
|
'email',
|
||||||
|
'country_of_residence',
|
||||||
|
'repositories',
|
||||||
|
'all_emails',
|
||||||
|
'period_begins',
|
||||||
|
'period_end_type',
|
||||||
|
'period_ends',
|
||||||
|
'agreement_terms',
|
||||||
|
'attestation_of_copyright',
|
||||||
|
]
|
||||||
|
|
||||||
|
def clean_period_ends(self):
|
||||||
|
cleaned_data = super().clean()
|
||||||
|
if 'period_begins' in cleaned_data and 'period_ends' in cleaned_data and cleaned_data['period_begins'] > cleaned_data['period_ends']:
|
||||||
|
raise ValidationError('End of period is before start')
|
|
@ -0,0 +1,74 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Generated by Django 1.11.29 on 2021-12-06 22:37
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
import datetime
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django_countries.fields
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('assignment', '0001_initial'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='assignment',
|
||||||
|
name='coverage',
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='assignment',
|
||||||
|
name='place_of_residence',
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='assignment',
|
||||||
|
name='repository',
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='assignment',
|
||||||
|
name='all_emails',
|
||||||
|
field=models.TextField(default='', verbose_name='All email addresses and/or names used by you to contribute to the above'),
|
||||||
|
preserve_default=False,
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='assignment',
|
||||||
|
name='country_of_residence',
|
||||||
|
field=django_countries.fields.CountryField(default='', max_length=2),
|
||||||
|
preserve_default=False,
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='assignment',
|
||||||
|
name='period_begins',
|
||||||
|
field=models.DateField(default=datetime.date(2021, 1, 1), verbose_name='Assignment period begins'),
|
||||||
|
preserve_default=False,
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='assignment',
|
||||||
|
name='period_end_type',
|
||||||
|
field=models.CharField(choices=[('all future contributions', 'all future contributions'), ('a specific past date', 'a specific past date')], default=datetime.date(2021, 1, 1), max_length=50, verbose_name='Time period to assign'),
|
||||||
|
preserve_default=False,
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='assignment',
|
||||||
|
name='period_ends',
|
||||||
|
field=models.DateField(blank=True, null=True, verbose_name='Assignment period ends (if applicable)'),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='assignment',
|
||||||
|
name='repositories',
|
||||||
|
field=models.TextField(default='', help_text='List of URLs, one per line', verbose_name="Code repositories contributed to that you'd like to assign"),
|
||||||
|
preserve_default=False,
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='assignment',
|
||||||
|
name='attestation_of_copyright',
|
||||||
|
field=models.BooleanField(verbose_name='I agree to be bound by the terms of the Copyright Assignment Agreement above, and that I own the copyright in the works defined above'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='assignment',
|
||||||
|
name='email',
|
||||||
|
field=models.EmailField(max_length=254, verbose_name='Email address (to contact you if we have questions)'),
|
||||||
|
),
|
||||||
|
]
|
|
@ -0,0 +1,25 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Generated by Django 1.11.29 on 2021-12-06 22:49
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
import uuid
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('assignment', '0002_auto_20211206_2237'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='assignment',
|
||||||
|
name='id',
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='assignment',
|
||||||
|
name='uuid',
|
||||||
|
field=models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False),
|
||||||
|
),
|
||||||
|
]
|
|
@ -1,33 +1,59 @@
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
import uuid
|
||||||
|
|
||||||
|
from django.core.validators import URLValidator, ValidationError
|
||||||
from django.db import models
|
from django.db import models
|
||||||
|
from django_countries.fields import CountryField
|
||||||
|
|
||||||
|
|
||||||
|
def validate_mutiple_urls(value):
|
||||||
|
"""Map the URLValidator() over text containing multiple URLs."""
|
||||||
|
candidate_urls = [c.strip() for c in value.split()]
|
||||||
|
invalid_urls = []
|
||||||
|
# TODO: Improve this https://docs.djangoproject.com/en/3.2/ref/forms/validation/#raising-multiple-errors
|
||||||
|
validator = URLValidator()
|
||||||
|
for url in candidate_urls:
|
||||||
|
try:
|
||||||
|
validator(url)
|
||||||
|
except ValidationError:
|
||||||
|
invalid_urls.append(url)
|
||||||
|
print(invalid_urls)
|
||||||
|
if invalid_urls:
|
||||||
|
raise ValidationError('These don\'t seem to be complete URLs:\n{}'.format('\n'.join(invalid_urls)))
|
||||||
|
|
||||||
|
|
||||||
class Assignment(models.Model):
|
class Assignment(models.Model):
|
||||||
"""A copyright assignment to Conservancy."""
|
"""A copyright assignment to Conservancy."""
|
||||||
|
|
||||||
|
uuid = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
|
||||||
full_name = models.CharField(max_length=255)
|
full_name = models.CharField(max_length=255)
|
||||||
email = models.EmailField()
|
email = models.EmailField('Email address (to contact you if we have questions)')
|
||||||
place_of_residence = models.TextField(
|
country_of_residence = CountryField()
|
||||||
'Country of citizenship or residential address',
|
repositories = models.TextField(
|
||||||
blank=True)
|
'Code repositories contributed to that you\'d like to assign',
|
||||||
|
help_text='List of URLs, one per line',
|
||||||
repository = models.URLField(
|
validators=[validate_mutiple_urls],
|
||||||
'Code repository',
|
|
||||||
blank=True,
|
|
||||||
)
|
)
|
||||||
coverage = models.CharField(
|
all_emails = models.TextField(
|
||||||
verbose_name='Time period to assign',
|
'All email addresses and/or names used by you to contribute to the above',
|
||||||
|
)
|
||||||
|
period_begins = models.DateField(
|
||||||
|
'Assignment period begins',
|
||||||
|
)
|
||||||
|
period_end_type = models.CharField(
|
||||||
|
'Time period to assign',
|
||||||
max_length=50,
|
max_length=50,
|
||||||
choices=[
|
choices=[
|
||||||
('up to this year', 'One-off up to and including this year'),
|
('all future contributions', 'all future contributions'),
|
||||||
('ongoing', 'All existing and new contributions'),
|
('a specific past date', 'a specific past date'),
|
||||||
('specific', 'A specific period (details below)'),
|
|
||||||
],
|
],
|
||||||
default='up to this year',
|
|
||||||
)
|
)
|
||||||
coverage_from = models.DateField(blank=True)
|
period_ends = models.DateField(
|
||||||
coverage_to = models.DateField(blank=True)
|
'Assignment period ends (if applicable)',
|
||||||
|
blank=True,
|
||||||
|
null=True,
|
||||||
|
)
|
||||||
attestation_of_copyright = models.BooleanField(
|
attestation_of_copyright = models.BooleanField(
|
||||||
'I attest that I own the copyright on these works'
|
'I agree to be bound by the terms of the Copyright Assignment Agreement above, and that I own the copyright in the works defined above',
|
||||||
)
|
)
|
||||||
|
|
121
www/conservancy/apps/assignment/terms.py
Normal file
121
www/conservancy/apps/assignment/terms.py
Normal file
|
@ -0,0 +1,121 @@
|
||||||
|
import textwrap
|
||||||
|
|
||||||
|
TERMS = textwrap.dedent("""\
|
||||||
|
Copyright Assignment Agreement
|
||||||
|
|
||||||
|
By checking the box below and submitting this form, you (``Assignor'')
|
||||||
|
enter into this Agreement between Assignor and
|
||||||
|
the Software Freedom Conservancy, Inc., a New York nonprofit corporation
|
||||||
|
located in Brooklyn, New York, which has received recognition of exemption
|
||||||
|
from federal income tax under Section 501(c)(3) of the Internal Revenue
|
||||||
|
Code and classification as a public charity (the ``Conservancy'').
|
||||||
|
|
||||||
|
For good and valuable consideration, receipt of which is hereby
|
||||||
|
acknowledged, Assignor hereby transfers to the Conservancy its entire
|
||||||
|
right, title, and interest (including all rights under copyright) in the
|
||||||
|
work identified by the repositories, email addresses, names, and time
|
||||||
|
periods listed above, including original code,
|
||||||
|
accompanying documentation and supporting files, changes and enhancements
|
||||||
|
to the code and accompanying files, subject to the conditions
|
||||||
|
below. The original code, files, changes and enhancements, and
|
||||||
|
modifications are herein called the ``Work''.
|
||||||
|
|
||||||
|
For the purposes of this contract, a work ``based on the Work'' means any
|
||||||
|
work that in whole or in part incorporates or is derived from all or part
|
||||||
|
of the Work. The Conservancy promises that the Work and any work ``based
|
||||||
|
on the Work'' distributed by the Conservancy or its assignees will be
|
||||||
|
distributed under one or more of the following licenses:
|
||||||
|
|
||||||
|
* the license as set forth in Exhibit A (the ``MIT License''),
|
||||||
|
|
||||||
|
* the GNU General Public License v2 or any later version (``GPL''),
|
||||||
|
as published by the Free Software Foundation, Inc.,
|
||||||
|
|
||||||
|
* the ``CC-By'' license as published by the Creative Commons, Inc.,
|
||||||
|
|
||||||
|
* the Creative Commons Attribution-ShareAlike 3.0 United States license
|
||||||
|
(``CC-By-SA''),
|
||||||
|
|
||||||
|
* any other license determined to be a free software license by the
|
||||||
|
Free Software Foundation (``FSF'') and approved as an open source
|
||||||
|
license by the Open Source Initiative (``OSI''),
|
||||||
|
|
||||||
|
* any other license determined to be a free culture compatible
|
||||||
|
license by the Creative Commons Corporation (``Creative
|
||||||
|
Commons'') and freedomdefined.org (``Freedom Defined'').
|
||||||
|
|
||||||
|
In the event that either FSF or OSI ceases to maintain a list of approved
|
||||||
|
licenses for a period of one year and, for a period of six months, fails
|
||||||
|
to respond to a written request from the Conservancy regarding evaluation
|
||||||
|
of a new license which is not currently listed on either approved lists
|
||||||
|
(is ``Dormant''), the work may be distributed under that new license,
|
||||||
|
provided that new license is approved as a free software or open source
|
||||||
|
license by one of FSF or OSI, and the Conservancy also independently
|
||||||
|
determines the new license will allow the software to be freely copied,
|
||||||
|
modified, and redistributed by all its users (is a ``Free License''). In
|
||||||
|
the event that both FSF and OSI are Dormant, the Work may be distributed
|
||||||
|
under a license the Conservancy independently determines is a Free
|
||||||
|
Software License.
|
||||||
|
|
||||||
|
In the event that either Creative Commons or Freedom Defined is Dormant,
|
||||||
|
the Work may be distributed under that new license, provided that new
|
||||||
|
license is approved as a free culture compatible license by one of the
|
||||||
|
Creative Commons or Freedom Defined, and the Conservancy also
|
||||||
|
independently determines the new license is a Free License. In the event
|
||||||
|
that both Creative Commons and Freedom Defined are Dormant, the Work may
|
||||||
|
be distributed under a license the Conservancy independently determines is
|
||||||
|
a Free Culture License.
|
||||||
|
|
||||||
|
The Conservancy promises that any program ``based on the Work'' offered to
|
||||||
|
the public by the Conservancy or its assignees shall be offered in a
|
||||||
|
machine-readable source format, in addition to any other forms of the
|
||||||
|
Conservancy's choosing. However, the Conservancy is free to choose at its
|
||||||
|
convenience the media of distribution for the machine-readable source
|
||||||
|
format.
|
||||||
|
|
||||||
|
The Conservancy hereby grants Assignor a royalty-free non-exclusive
|
||||||
|
license to use or sub-license the interests assigned hereunder for any
|
||||||
|
purpose. The Conservancy's rights shall otherwise continue unchanged.
|
||||||
|
|
||||||
|
Assignor hereby grants to the Conservancy and to recipients of software
|
||||||
|
distributed by the Conservancy a perpetual, worldwide, non-exclusive,
|
||||||
|
no-charge, royalty-free, irrevocable patent license to make, have made,
|
||||||
|
use, offer to sell, sell, import, and otherwise transfer the Work, where
|
||||||
|
such license applies only to those patent claims licensable by Assignor
|
||||||
|
that are necessarily infringed by the Work alone or by combination of
|
||||||
|
Assignor's contributions with the Work to which such contributions were
|
||||||
|
submitted.
|
||||||
|
|
||||||
|
Assignor hereby represents and warrants that it is the sole copyright
|
||||||
|
holder for the Work assigned hereunder and that it has the right and power
|
||||||
|
to enter into this contract. Assignor hereby indemnifies and holds
|
||||||
|
harmless the Conservancy, its officers, employees, and agents against any
|
||||||
|
and all claims, actions or damages (including reasonable attorney's fees)
|
||||||
|
asserted by or paid to any party on account of a breach or alleged breach
|
||||||
|
of the foregoing warranty. Assignor makes no other express or implied
|
||||||
|
warranty (including without limitation, in this disclaimer of warranty,
|
||||||
|
any warranty of <em>merchantability</em> or <em>fitness for a particular
|
||||||
|
purpose</em>).
|
||||||
|
|
||||||
|
|
||||||
|
Exhibit A
|
||||||
|
The MIT License
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
copy of this software and associated documentation files (the
|
||||||
|
``Software''), to deal in the Software without restriction, including
|
||||||
|
without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
distribute, sublicense, and/or sell copies of the Software, and to permit
|
||||||
|
persons to whom the Software is furnished to do so, subject to the
|
||||||
|
following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
<em>The software is provided ``as is'', without warranty of any kind, express or
|
||||||
|
implied, including but not limited to the warranties of merchantability,
|
||||||
|
fitness for a particular purpose and noninfringement. In no event shall
|
||||||
|
the authors or copyright holders be liable for any claim, damages or other
|
||||||
|
liability, whether in an action of contract, tort or otherwise, arising
|
||||||
|
from, out of or in connection with the software or the use or other
|
||||||
|
dealings in the software.</em>""")
|
|
@ -5,5 +5,5 @@ from .views import AssignmentCreateView, AssignmentThanksView
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
url(r'^$', AssignmentCreateView.as_view(), name='assignement-add'),
|
url(r'^$', AssignmentCreateView.as_view(), name='assignement-add'),
|
||||||
url(r'^thanks/$', AssignmentThanksView.as_view(), name='assignment-thanks'),
|
url(r'^(?P<pk>[\w-]+)/$', AssignmentThanksView.as_view(), name='assignment-thanks'),
|
||||||
]
|
]
|
||||||
|
|
|
@ -1,31 +1,39 @@
|
||||||
from django import forms
|
from django.core.mail import send_mail
|
||||||
from django.urls import reverse_lazy
|
from django.urls import reverse_lazy
|
||||||
from django.views.generic import TemplateView
|
from django.views.generic import DetailView
|
||||||
from django.views.generic.edit import CreateView
|
from django.views.generic.edit import CreateView
|
||||||
|
|
||||||
|
from .forms import AssignmentForm
|
||||||
from .models import Assignment
|
from .models import Assignment
|
||||||
|
|
||||||
|
|
||||||
class AssignmentForm(forms.ModelForm):
|
|
||||||
model = Assignment
|
|
||||||
coverage_from = forms.DateField(required=False)
|
|
||||||
coverage_to = forms.DateField(required=False)
|
|
||||||
|
|
||||||
|
|
||||||
class AssignmentCreateView(CreateView):
|
class AssignmentCreateView(CreateView):
|
||||||
"""Show a form for the initial copyright assignment."""
|
"""Show a form for the initial copyright assignment."""
|
||||||
|
|
||||||
form_class = AssignmentForm
|
form_class = AssignmentForm
|
||||||
fields = [
|
template_name = 'assignment/assignment_form.html'
|
||||||
'full_name',
|
|
||||||
'email',
|
def form_valid(self, form):
|
||||||
'place_of_residence',
|
intro = 'The following copyright assignment has been submitted:\n\n'
|
||||||
'repository',
|
body = intro + '\n'.join(['{}: {}'.format(k, v) for k, v in form.cleaned_data.items() if k != 'agreement_terms'])
|
||||||
'coverage',
|
send_mail(
|
||||||
'attestation_of_copyright',
|
'Copyright assignment form: {}'.format(form.cleaned_data['full_name']),
|
||||||
]
|
body,
|
||||||
success_url = reverse_lazy('assignment-thanks')
|
'ben@sturm.com.au',
|
||||||
|
['denver@sfconservancy.org', 'bsturmfels@sfconservancy.org'],
|
||||||
|
)
|
||||||
|
return super().form_valid(form)
|
||||||
|
|
||||||
|
def get_success_url(self, *args, **kwargs):
|
||||||
|
return reverse_lazy('assignment-thanks', kwargs={'pk': str(self.object.uuid)})
|
||||||
|
|
||||||
|
|
||||||
class AssignmentThanksView(TemplateView):
|
class AssignmentThanksView(DetailView):
|
||||||
|
model = Assignment
|
||||||
template_name = 'assignment/thanks.html'
|
template_name = 'assignment/thanks.html'
|
||||||
|
|
||||||
|
def get_context_data(self, **kwargs):
|
||||||
|
context = super().get_context_data(**kwargs)
|
||||||
|
context['form'] = AssignmentForm(instance=self.object)
|
||||||
|
for _, field in context['form'].fields.items():
|
||||||
|
field.widget.attrs['disabled'] = 'disabled'
|
||||||
|
return context
|
||||||
|
|
|
@ -84,3 +84,25 @@ LOGGING = {
|
||||||
'level': 'INFO',
|
'level': 'INFO',
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
INSTALLED_APPS = [
|
||||||
|
'django.contrib.auth',
|
||||||
|
'django.contrib.contenttypes',
|
||||||
|
'django.contrib.sessions',
|
||||||
|
'django.contrib.sites',
|
||||||
|
'django.contrib.admin',
|
||||||
|
'django.contrib.messages',
|
||||||
|
'django.contrib.humanize',
|
||||||
|
# 'django.contrib.staticfiles',
|
||||||
|
'conservancy.apps.blog',
|
||||||
|
'conservancy.apps.contacts',
|
||||||
|
'conservancy.apps.contractpatch',
|
||||||
|
'conservancy.apps.events',
|
||||||
|
'conservancy.apps.news',
|
||||||
|
'conservancy.apps.staff',
|
||||||
|
# 'conservancy.apps.summit_registration',
|
||||||
|
'conservancy.apps.worldmap',
|
||||||
|
'conservancy.apps.supporters',
|
||||||
|
'conservancy.apps.fundgoal',
|
||||||
|
'conservancy.apps.assignment',
|
||||||
|
]
|
||||||
|
|
|
@ -1,38 +1,20 @@
|
||||||
{% extends "base_conservancy.html" %}
|
{% extends "assignment/base_assignment.html" %}
|
||||||
{% block category %}Copyright Assignment{% endblock %}
|
{% block category %}Copyright Assignment{% endblock %}
|
||||||
{% block outercontent %}
|
{% block outercontent %}
|
||||||
<style>
|
|
||||||
label { display: block; }
|
|
||||||
input, textarea, select {
|
|
||||||
width: 25rem;
|
|
||||||
padding: 0.25rem;
|
|
||||||
border-radius: 2px;
|
|
||||||
}
|
|
||||||
input[type=checkbox] { width: auto; }
|
|
||||||
span[class=helptext] {
|
|
||||||
display: block;
|
|
||||||
font-size: 12px;
|
|
||||||
font-style: italic;
|
|
||||||
color: #666;
|
|
||||||
}
|
|
||||||
#id_place_of_residence {
|
|
||||||
height: 5rem;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
<h1>Copyright Assignment</h1>
|
<h1>Copyright Assignment</h1>
|
||||||
|
|
||||||
<div class="mw7">
|
<div class="mw7 mb5">
|
||||||
<p>Thank you for considering assigning your copyright to the Software Freedom Conservancy. Your assignment helps us enforce copyright on your behalf.</p>
|
<p>Thank you for considering assigning your copyright to the Software Freedom Conservancy. Your assignment helps us enforce free and open source software licenses.</p>
|
||||||
|
|
||||||
<p>Please complete the following form and we will prepare the appropriate paperwork. You will receive a PDF form to sign and be witnessed by a public notary.</p>
|
<p>By filling in and submitting the below form, you agree to assign your copyrights in the specified projects to Software Freedom Conservancy, which means that Conservancy can enforce the licenses that your code is under in court, without you needing to be involved. Conservancy agrees to keep your code under a free and open source license.</p>
|
||||||
</div>
|
|
||||||
|
<p>If you have any questions about assigning your copyright to Conservancy, please don't hesitate to email us at <a href="mailto:info@sfconservancy.org">info@sfconservancy.org</a>.</p>
|
||||||
|
|
||||||
<form action="." method="post" class="mw7">
|
<form action="." method="post" class="mw7">
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
{{ form.as_p }}
|
{{ form.as_p }}
|
||||||
|
|
||||||
<p><em>Please be aware that some employment agreements explicitly transfer copyright ownership to the employer. We recommend you review your recent employment agreements for such clauses.</em></p>
|
|
||||||
|
|
||||||
<p><button type="submit" class="ph3 pv2">Next</button></p>
|
<p><button type="submit" class="ph3 pv2">Next</button></p>
|
||||||
</form>
|
</form>
|
||||||
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
|
@ -1,27 +1,14 @@
|
||||||
{% extends "base_conservancy.html" %}
|
{% extends "assignment/base_assignment.html" %}
|
||||||
|
{% load static %}
|
||||||
{% block category %}Copyright Assignment{% endblock %}
|
{% block category %}Copyright Assignment{% endblock %}
|
||||||
{% block outercontent %}
|
{% block outercontent %}
|
||||||
<style>
|
<h1>Thanks! <svg style="color: #ff41b4; width: 30px; height: 30px; vertical-align: middle;"><use href="{% static 'img/font_awesome.svg' %}#heart"></use></svg></h1>
|
||||||
label { display: block; }
|
|
||||||
input, textarea, select {
|
|
||||||
width: 25rem;
|
|
||||||
padding: 0.25rem;
|
|
||||||
border-radius: 2px;
|
|
||||||
}
|
|
||||||
input[type=checkbox] { width: auto; }
|
|
||||||
span[class=helptext] {
|
|
||||||
display: block;
|
|
||||||
font-size: 12px;
|
|
||||||
font-style: italic;
|
|
||||||
color: #666;
|
|
||||||
}
|
|
||||||
#id_place_of_residence {
|
|
||||||
height: 5rem;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
<h1>Thanks!</h1>
|
|
||||||
|
|
||||||
<div class="mw7">
|
<div class="mw7 mb5">
|
||||||
<p>You'll shortly receive an email with the paperwork required to complete this assignment. If you have any questions or concerns, please don't hesitate to <a href="/about/contact/">contact us</a>.</p>
|
<p>Thank you for assigning your copyright to Software Freedom Conservancy! We have recorded the below information regarding the assignment and the works.</p>
|
||||||
|
<p>If you would like to make any changes, you must let us know within 7 days by emailing <a href="mailto:info@sfconservancy.org">info@sfconservancy.org</a>. Thanks for helping us enforce free and open source software licenses!</p>
|
||||||
|
<form>
|
||||||
|
{{ form.as_p }}
|
||||||
|
</form>
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
Loading…
Reference in a new issue