Skip to content

Commit 00d7593

Browse files
committed
Merge branch 'master' into tag_cache_fix
2 parents 0445533 + 21c7214 commit 00d7593

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

47 files changed

+453
-892
lines changed

Dockerfile

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# https://hub.docker.com/r/nikolaik/python-nodejs
2-
FROM nikolaik/python-nodejs:python3.8-nodejs12
2+
FROM nikolaik/python-nodejs:python3.8-nodejs12
33

44
# Replace shell with bash so we can source files
55
RUN rm /bin/sh && ln -s /bin/bash /bin/sh
@@ -62,7 +62,7 @@ ENV HEADER_ALERT="<p>You are invited to our upcoming event, St. Hat-trick's day!
6262
ENV SPONSORS_METADATA='[{"displayName":"Textio","url":"https://medium.com/democracylab-org/textio-engages-employees-to-accelerate-civic-innovation-5984609a95ce","thumbnailUrl":"https://d1agxr2dqkgkuy.cloudfront.net/img/textio_logo_315_trans.png","description":"Textio is the inventor of augmented writing. Textio transforms your rough ideas into powerful language by hitting Tab."},{"displayName":"HERE Technologies","url":"https://www.here.com/","thumbnailUrl":"https://d1agxr2dqkgkuy.cloudfront.net/img/here_technologies.png","description":"By building a digital representation of reality entirely built upon location data, we are radically transforming the way the world lives, moves and interacts"},{"displayName":"Amazon","url":"https://www.aboutamazon.com/our-communities/amazon-in-the-community","thumbnailUrl":"https://d1agxr2dqkgkuy.cloudfront.net/img/amazon_logo.png","description":"At Amazon, we focus on building long-term and innovative programs that will have a lasting, positive impact in communities around the world."}]'
6363

6464
# Configure project description example link
65-
ENV PROJECT_DESCRIPTION_EXAMPLE_URL "https://www.democracylab.org/index/?section=AboutProject&id=1"
65+
ENV PROJECT_DESCRIPTION_EXAMPLE_URL "https://www.democracylab.org/projects/1"
6666

6767
# Configure position description example link
6868
ENV POSITION_DESCRIPTION_EXAMPLE_URL "https://docs.google.com/document/d/142NH4uRblJP6XvKdmW4GiFwoOmVWY6BJfEjGrlSP3Uk/edit"

civic.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,6 @@
1616
"partners": [],
1717
"data": [],
1818
"tags": [],
19-
"links": ["https://www.democracylab.org/index/?section=AboutProject&id=1"],
19+
"links": ["https://www.democracylab.org/projects/1"],
2020
"id": "https://raw.githubusercontent.com/DCgov/civic.json/master/schemas/schema-v1.json"
2121
}

civictechprojects/helpers/context_preload.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
def about_project_preload(context, request):
1010
context = default_preload(context, request)
1111
query_args = url_params(request)
12-
project_id = query_args['id'][0]
12+
project_id = query_args['id']
1313
project_json = ProjectCache.get(project_id)
1414
if project_json is not None:
1515
context['title'] = project_json['project_name'] + ' | DemocracyLab'
@@ -24,7 +24,7 @@ def about_project_preload(context, request):
2424
def about_event_preload(context, request):
2525
context = default_preload(context, request)
2626
query_args = url_params(request)
27-
event_id = query_args['id'][0]
27+
event_id = query_args['id']
2828
event = Event.get_by_id_or_slug(event_id)
2929
event_json = event.hydrate_to_json()
3030
if event_json is not None:
@@ -40,7 +40,7 @@ def about_event_preload(context, request):
4040
def about_group_preload(context, request):
4141
context = default_preload(context, request)
4242
query_args = url_params(request)
43-
group_id = query_args['id'][0]
43+
group_id = query_args['id']
4444
group_json = GroupCache.get(group_id)
4545
if group_json is not None:
4646
context['title'] = group_json['group_name'] + ' | DemocracyLab'

civictechprojects/sitemaps.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ def items(self):
2626
return self.pages
2727

2828
def location(self, page):
29-
return '/index/?section=' + page
29+
return section_path(page)
3030

3131

3232
class ProjectSitemap(Sitemap):

civictechprojects/urls.py

Lines changed: 24 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,12 @@
1313
1. Import the include() function: from django.conf.urls import url, include
1414
2. Add a URL to urlpatterns: url(r'^blog/', include('blog.urls'))
1515
"""
16-
from django.conf.urls import url
16+
from django.conf.urls import url, include
1717
from django.views.generic import TemplateView
18+
from django.contrib import admin
1819
from django.contrib.sitemaps.views import sitemap
1920
from common.helpers.error_handlers import handle500
21+
from common.urls import v1_urls, v2_urls
2022
from .sitemaps import ProjectSitemap, SectionSitemap, GroupSitemap, EventSitemap
2123

2224

@@ -39,22 +41,18 @@
3941
),
4042
url(r'^robots\.txt$', views.robots, name='robots'),
4143
url(r'^googlebb20bcf8545e7046.html$', TemplateView.as_view(template_name="googlebb20bcf8545e7046.html")),
42-
url(r'^groups/create/$', views.group_create, name='group_create'),
43-
url(r'^groups/approve/(?P<group_id>[0-9]+)/$', views.approve_group, name='approve_group'),
44-
url(r'^groups/edit/(?P<group_id>[0-9]+)/$', views.group_edit, name='group_edit'),
45-
url(r'^groups/delete/(?P<group_id>[0-9]+)/$', views.group_delete, name='group_delete'),
46-
url(r'^groups/(?P<group_id>[0-9]+)/add_project/$', views.group_add_project, name='group_add_project'),
47-
url(r'^groups/(?P<group_id>[0-9]+)/remove_project/$', views.group_delete_project, name='group_remove_project'),
48-
url(r'^events/create/$', views.event_create, name='event_create'),
49-
url(r'^events/approve/(?P<event_id>[0-9]+)/$', views.approve_event, name='approve_event'),
50-
url(r'^events/edit/(?P<event_id>[0-9]+)/$', views.event_edit, name='event_edit'),
51-
url(r'^events/delete/(?P<event_id>[0-9]+)/$', views.event_delete, name='event_delete'),
52-
url(r'^events/(?P<event_id>[0-9]+)/add_project/$', views.event_add_project, name='event_add_project'),
53-
url(r'^events/(?P<event_id>[0-9]+)/remove_project/$', views.event_delete_project, name='event_remove_project'),
54-
url(r'^projects/edit/(?P<project_id>[0-9]+)/$', views.project_edit, name='project_edit'),
55-
url(r'^projects/delete/(?P<project_id>[0-9]+)/$', views.project_delete, name='project_delete'),
56-
url(r'^projects/signup/$', views.project_create, name='project_create'),
57-
url(r'^projects/approve/(?P<project_id>[0-9]+)/$', views.approve_project, name='approve_project'),
44+
url(r'^api/groups/create/$', views.group_create, name='group_create'),
45+
url(r'^api/groups/approve/(?P<group_id>[0-9]+)/$', views.approve_group, name='approve_group'),
46+
url(r'^api/groups/edit/(?P<group_id>[0-9]+)/$', views.group_edit, name='group_edit'),
47+
url(r'^api/groups/delete/(?P<group_id>[0-9]+)/$', views.group_delete, name='group_delete'),
48+
url(r'^api/events/create/$', views.event_create, name='event_create'),
49+
url(r'^api/events/approve/(?P<event_id>[0-9]+)/$', views.approve_event, name='approve_event'),
50+
url(r'^api/events/edit/(?P<event_id>[0-9]+)/$', views.event_edit, name='event_edit'),
51+
url(r'^api/events/delete/(?P<event_id>[0-9]+)/$', views.event_delete, name='event_delete'),
52+
url(r'^api/projects/edit/(?P<project_id>[0-9]+)/$', views.project_edit, name='project_edit'),
53+
url(r'^api/projects/delete/(?P<project_id>[0-9]+)/$', views.project_delete, name='project_delete'),
54+
url(r'^api/projects/create/$', views.project_create, name='project_create'),
55+
url(r'^api/projects/approve/(?P<project_id>[0-9]+)/$', views.approve_project, name='approve_project'),
5856
url(
5957
r'^presign_s3/upload/project/thumbnail/$',
6058
views.presign_project_thumbnail_upload,
@@ -73,18 +71,21 @@
7371
url(r'^api/my_groups', views.my_groups),
7472
url(r'^api/tags/groups', views.group_tags_counts),
7573
url(r'^api/tags', views.tags),
76-
url(r'^index/$', views.index),
74+
url(r'^admin/', admin.site.urls),
75+
url(r'^contact/democracylab$', views.contact_democracylab, name='contact_democracylab'),
76+
url(r'^contact/project/(?P<project_id>[0-9]+)/$', views.contact_project_owner, name='contact_project_owner'),
77+
url(r'^contact/volunteers/(?P<project_id>[0-9]+)/$', views.contact_project_volunteers, name='contact_project_volunteers'),
78+
url(r'^contact/volunteer/(?P<application_id>[0-9]+)/$', views.contact_project_volunteer, name='contact_project_volunteer'),
79+
url(r'^contact/group/(?P<group_id>[0-9]+)/$', views.contact_group_owner, name='contact_group_owner'),
80+
url(r'', include(v2_urls)),
81+
url(r'', include(v1_urls)),
7782
url(r'^api/team$', views.team, name='team'),
7883
url(r'^api/project/(?P<project_id>[0-9]+)/$', views.get_project, name='get_project'),
7984
url(r'^api/group/(?P<group_id>[0-9]+)/invite$', views.invite_project_to_group, name='invite_project_to_group'),
8085
url(r'^api/invite/(?P<invite_id>[0-9]+)/approve$', views.accept_group_invitation, name='accept_group_invitation'),
8186
url(r'^api/invite/(?P<invite_id>[0-9]+)/reject$', views.reject_group_invitation, name='reject_group_invitation'),
8287
url(r'^api/group/(?P<group_id>[0-9]+)/$', views.get_group, name='get_group'),
8388
url(r'^api/event/(?P<event_id>.*)/$', views.get_event, name='get_event'),
84-
url(r'^contact/project/(?P<project_id>[0-9]+)/$', views.contact_project_owner, name='contact_project_owner'),
85-
url(r'^contact/volunteers/(?P<project_id>[0-9]+)/$', views.contact_project_volunteers, name='contact_project_volunteers'),
86-
url(r'^contact/volunteer/(?P<application_id>[0-9]+)/$', views.contact_project_volunteer, name='contact_project_volunteer'),
87-
url(r'^contact/group/(?P<group_id>[0-9]+)/$', views.contact_group_owner, name='contact_group_owner'),
8889
url(r'^volunteer/(?P<project_id>[0-9]+)/$', views.volunteer_with_project, name='volunteer_with_project'),
8990
url(r'^volunteer/leave/(?P<project_id>[0-9]+)/$', views.leave_project, name='leave_project'),
9091
url(r'^volunteer/approve/(?P<application_id>[0-9]+)/$', views.accept_project_volunteer, name='accept_project_volunteer'),
@@ -94,8 +95,7 @@
9495
url(r'^volunteer/demote/(?P<application_id>[0-9]+)/$', views.demote_project_volunteer, name='demote_project_volunteer'),
9596
url(r'^volunteer/renew/(?P<application_id>[0-9]+)/$', views.renew_volunteering_with_project, name='renew_volunteering_with_project'),
9697
url(r'^volunteer/conclude/(?P<application_id>[0-9]+)/$', views.conclude_volunteering_with_project, name='conclude_volunteering_with_project'),
97-
url(r'^alert/create/$', views.add_alert, name='add_alert'),
98-
url(r'^contact/democracylab$', views.contact_democracylab, name='contact_democracylab')
98+
url(r'^alert/create/$', views.add_alert, name='add_alert')
9999

100100
]
101101

civictechprojects/views.py

Lines changed: 18 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import re
12
from django.shortcuts import redirect
23
from django.http import HttpResponse, HttpResponseForbidden, JsonResponse
34
from django.core.exceptions import PermissionDenied
@@ -121,7 +122,7 @@ def group_edit(request, group_id):
121122
if request.is_ajax():
122123
return JsonResponse(group.hydrate_to_json())
123124
else:
124-
return redirect('/index/?section=AboutGroup&id=' + group_id)
125+
return redirect(section_url(FrontEndSection.AboutGroup, {'id': group_id}))
125126

126127

127128
# TODO: Pass csrf token in ajax call so we can check for it
@@ -148,39 +149,6 @@ def get_group(request, group_id):
148149
else:
149150
return HttpResponse(status=404)
150151

151-
@csrf_exempt
152-
def group_add_project(request, group_id):
153-
body = json.loads(request.body)
154-
group = Group.objects.get(id=group_id)
155-
156-
if group is not None and body["project_ids"] is not None:
157-
if not is_creator_or_staff(get_request_contributor(request), group):
158-
return HttpResponseForbidden()
159-
160-
projects = Project.objects.filter(id__in=body["project_ids"])
161-
162-
for project in projects:
163-
ProjectRelationship.create(group, project)
164-
165-
return HttpResponse(status=204)
166-
else:
167-
return HttpResponse(status=404)
168-
169-
def group_delete_project(request, group_id):
170-
body = json.loads(request.body)
171-
group = Group.objects.get(id=group_id)
172-
project = Project.objects.get(id=body["project_id"])
173-
174-
if group is not None and project is not None:
175-
if is_creator_or_staff(get_request_contributor(request), group):
176-
relationship = ProjectRelationship.objects.get(relationship_project=project.id, relationship_group=group.id)
177-
178-
if relationship is not None:
179-
relationship.delete()
180-
return HttpResponse(status=204)
181-
182-
return HttpResponse(status=404)
183-
184152

185153
def approve_group(request, group_id):
186154
group = Group.objects.get(id=group_id)
@@ -234,7 +202,7 @@ def event_edit(request, event_id):
234202
if request.is_ajax():
235203
return JsonResponse(event.hydrate_to_json())
236204
else:
237-
return redirect('/index/?section=AboutEvent&id=' + event_id)
205+
return redirect(section_url(FrontEndSection.AboutEvent, {'id': event_id}))
238206

239207

240208
# TODO: Pass csrf token in ajax call so we can check for it
@@ -262,38 +230,6 @@ def get_event(request, event_id):
262230
return JsonResponse(event.hydrate_to_json()) if event else HttpResponse(status=404)
263231

264232

265-
def event_add_project(request, event_id):
266-
body = json.loads(request.body)
267-
event = Event.objects.get(id=event_id)
268-
269-
if event is not None and body["project_ids"] is not None:
270-
if not is_creator_or_staff(get_request_contributor(request), event):
271-
return HttpResponseForbidden()
272-
273-
projects = Project.objects.filter(id__in=body["project_ids"])
274-
275-
for project in projects:
276-
ProjectRelationship.create(event, project)
277-
278-
return HttpResponse(status=204)
279-
else:
280-
return HttpResponse(status=404)
281-
282-
def event_delete_project(request, event_id):
283-
body = json.loads(request.body)
284-
event = Event.objects.get(id=event_id)
285-
project = Project.objects.get(id=body["project_id"])
286-
287-
if event is not None and project is not None:
288-
if is_creator_or_staff(get_request_contributor(request), event):
289-
relationship = ProjectRelationship.objects.get(relationship_project=project.id, relationship_event=event.id)
290-
291-
if relationship is not None:
292-
relationship.delete()
293-
return HttpResponse(status=204)
294-
295-
return HttpResponse(status=404)
296-
297233
# TODO: Pass csrf token in ajax call so we can check for it
298234
@csrf_exempt
299235
def project_create(request):
@@ -323,7 +259,7 @@ def project_edit(request, project_id):
323259
if request.is_ajax():
324260
return JsonResponse(project.hydrate_to_json())
325261
else:
326-
return redirect('/index/?section=AboutProject&id=' + project_id)
262+
return redirect(section_url(FrontEndSection.AboutProject, {'id': project_id}))
327263

328264

329265
# TODO: Pass csrf token in ajax call so we can check for it
@@ -364,7 +300,7 @@ def approve_project(request, project_id):
364300
SitemapPages.update()
365301
notify_project_owners_project_approved(project)
366302
messages.success(request, 'Project Approved')
367-
return redirect('/index/?section=AboutProject&id=' + str(project.id))
303+
return redirect(section_url(FrontEndSection.AboutProject, {'id': project_id}))
368304
else:
369305
return HttpResponseForbidden()
370306
else:
@@ -391,7 +327,7 @@ def approve_event(request, event_id):
391327

392328
@ensure_csrf_cookie
393329
@xframe_options_exempt
394-
def index(request):
330+
def index(request, id=None):
395331
page_url = request.get_full_path()
396332
clean_url = get_clean_url(page_url)
397333
if clean_url != page_url:
@@ -1271,6 +1207,7 @@ def reject_group_invitation(request, invite_id):
12711207

12721208
#This will ask Google if the recaptcha is valid and if so send email, otherwise return an error.
12731209
#TODO: Return text strings to be displayed on the front end so we know specifically what happened
1210+
#TODO: Figure out why changing the endpoint to /api/contact/democracylab results in CSRF issues
12741211
@csrf_exempt
12751212
def contact_democracylab(request):
12761213
#first prepare all the data from the request body
@@ -1319,3 +1256,14 @@ def team(request):
13191256

13201257
return JsonResponse(response)
13211258

1259+
1260+
def redirect_v1_urls(request):
1261+
page_url = request.get_full_path()
1262+
print(page_url)
1263+
clean_url = get_clean_url(page_url)
1264+
print('Redirecting v1 url: ' + clean_url)
1265+
section_match = re.findall(r'/index/\?section=(\w+)', clean_url)
1266+
section_name = section_match[0] if len(section_match) > 0 else FrontEndSection.Home
1267+
section_id_match = re.findall(r'&id=([\w-]+)', clean_url)
1268+
section_id = section_id_match[0] if len(section_id_match) > 0 else ''
1269+
return redirect(section_url(section_name, {'id': section_id}))

common/components/chrome/MainHeader.jsx

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,14 @@ import NavDropdown from "react-bootstrap/NavDropdown";
2525
import Dropdown from "react-bootstrap/Dropdown";
2626
import Button from "react-bootstrap/Button";
2727
import UserIcon from "../svg/user-circle-solid.svg";
28+
import { Dictionary } from "../types/Generics.jsx";
2829

2930
type State = {|
3031
showMyProjects: boolean,
3132
showMyGroups: boolean,
3233
showMyEvents: boolean,
3334
showHeader: boolean,
35+
loginUrl: string,
3436
|};
3537

3638
class MainHeader extends React.Component<{||}, State> {
@@ -52,6 +54,7 @@ class MainHeader extends React.Component<{||}, State> {
5254
showMyEvents:
5355
myEvents &&
5456
(!_.isEmpty(myEvents.owned_events) || CurrentUser.isStaff()),
57+
loginUrl: url.logInThenReturn(),
5558
};
5659
}
5760
// may need activeSection: NavigationStore.getSection() in calculateState, check that
@@ -98,7 +101,7 @@ class MainHeader extends React.Component<{||}, State> {
98101
<Button
99102
className="MainHeader-showmobile MainHeader-login-button"
100103
variant="outline-primary"
101-
href={url.section(Section.LogIn, url.getPreviousPageArg())}
104+
href={this.state.loginUrl}
102105
>
103106
Log In
104107
</Button>
@@ -147,7 +150,7 @@ class MainHeader extends React.Component<{||}, State> {
147150
) : (
148151
<Nav.Link
149152
className="MainHeader-showmobile"
150-
href={url.section(Section.LogIn, url.getPreviousPageArg())}
153+
href={this.state.loginUrl}
151154
>
152155
Log In
153156
</Nav.Link>
@@ -199,7 +202,7 @@ class MainHeader extends React.Component<{||}, State> {
199202
<Button
200203
className="MainHeader-showdesktop MainHeader-login-button"
201204
variant="outline-primary"
202-
href={url.section(Section.LogIn, url.getPreviousPageArg())}
205+
href={this.state.loginUrl}
203206
>
204207
Log In
205208
</Button>
@@ -210,8 +213,7 @@ class MainHeader extends React.Component<{||}, State> {
210213
//TODO: Refactor these to reduce duplication
211214
//TODO: Allow multiple arguments for url.section to handle url.getPreviousPageArg() - options object?
212215
_renderNavLink(section, text, classes = "") {
213-
const urlArgs = url.arguments(url.section(section));
214-
if (urlArgs.section === this.state.activeSection) {
216+
if (section === this.state.activeSection) {
215217
classes += " MainHeader-active";
216218
}
217219
return (
@@ -221,8 +223,7 @@ class MainHeader extends React.Component<{||}, State> {
221223
);
222224
}
223225
_renderNavDropdownItem(section, text, classes = "") {
224-
const urlArgs = url.arguments(url.section(section));
225-
if (urlArgs.section === this.state.activeSection) {
226+
if (section === this.state.activeSection) {
226227
classes += " MainHeader-active";
227228
}
228229
return (

common/components/common/groups/ContactGroupButton.jsx

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -133,9 +133,7 @@ class ContactGroupButton extends React.PureComponent<Props, State> {
133133
type="button"
134134
disabled={this.state.buttonDisabled}
135135
title={this.state.buttonTitle}
136-
href={`/index/?section=LogIn&prev=${
137-
window.location.href.split("?section=")[1]
138-
}`}
136+
href={url.logInThenReturn()}
139137
>
140138
Sign in to Contact Group
141139
</Button>

0 commit comments

Comments
 (0)