Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,13 @@ Development (master)
- Fix checkboxgroup value filtering in the admin to work with arrays of selected values

* New Features:
- ...
- Allow placing the map at a path other than the host root.

* Upgrade Steps:
- ...
- If you want to take advantage of the new relative paths, you will need to update your templates and CSS files:
- Go through your HTML templates, ensure you're using the `{% static %}` tag to include static files, and update any paths that are not relative to use the `{{route_prefix}}` variable (i.e. `"/places/"` would become `"{{route_prefix}}/places/"}}`).
- Go through your jstemplates and search for href. Update any internal paths to use the new `{{prefix "..."}}` helper.
- Go through your CSS and search for `url(/static/...)`. Ensure that these use relative paths instead (in CSS, `url(...)` paths are relative to the CSS file location).

4.1.0
-----------------------------
Expand Down
11 changes: 11 additions & 0 deletions doc/CONFIG.md
Original file line number Diff line number Diff line change
Expand Up @@ -500,3 +500,14 @@ To change the subject or body of the email that is sent to users, create templat
### Styling

See [Customizing the Theme](CUSTOM_THEME.md)

## Step 4: Deploying your map

There are a few important environment variables that you can set:

`SHAREABOUTS_FLAVOR` - The name of the flavor you created in Step 2. This is required.
`SHAREABOUTS_DATASET_ROOT` - The URL to your dataset root. This is required.
`SHAREABOUTS_DATASET_KEY` - The API key for your dataset. This is optional.
`BASE_URL` - If you want to run Shareabouts under a subpath, set this to the path you want to use. For example, if you want to run Shareabouts under `http://example.com/subpath/`, set this to `/subpath/`. **NOTE: unless this is a full URL, it should probably start with a slash, and if it's a path it should probably end in a slash as well.** This is optional.

For more information see [Deploying Your Map](DEPLOY.md)
18 changes: 9 additions & 9 deletions src/flavors/defaultflavor/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ map:

# GeoJSON Layers
# ==============
- url: /static/data/philadelphia.geojson
- url: "{{static_url}}/data/philadelphia.geojson"
type: json
rules:
- condition: 'true'
Expand Down Expand Up @@ -85,16 +85,16 @@ place_types:
# Display landmarks as icons when zoomed in

icon:
iconUrl: /static/css/images/markers/dot-0d85e9.png
iconUrl: "{{static_url}}/css/images/markers/dot-0d85e9.png"
iconSize: [17, 18]
iconAnchor: [9, 9]

- condition: '"{{location_type}}" === "landmark" && {{layer.focused}} === true'
# Display landmarks as icons when focused/selected

icon:
iconUrl: /static/css/images/markers/marker-0d85e9.png
shadowUrl: /static/css/images/marker-shadow.png
iconUrl: "{{static_url}}/css/images/markers/marker-0d85e9.png"
shadowUrl: "{{static_url}}/css/images/marker-shadow.png"
iconSize: [25, 41]
shadowSize: [41, 41]
iconAnchor: [12, 41]
Expand All @@ -106,8 +106,8 @@ place_types:
# Show parks that are points as icons...

icon:
iconUrl: /static/css/images/markers/marker-4bbd45.png
shadowUrl: /static/css/images/marker-shadow.png
iconUrl: "{{static_url}}/css/images/markers/marker-4bbd45.png"
shadowUrl: "{{static_url}}/css/images/marker-shadow.png"
iconSize: [25, 41]
shadowSize: [41, 41]
iconAnchor: [12, 41]
Expand All @@ -124,7 +124,7 @@ place_types:
# Show parks that are points as icons...

icon:
iconUrl: /static/css/images/markers/dot-4bbd45.png
iconUrl: "{{static_url}}/css/images/markers/dot-4bbd45.png"
iconSize: [17, 18]
iconAnchor: [9, 9]

Expand Down Expand Up @@ -362,11 +362,11 @@ pages:
pages:
- title: _(Why Shareabouts?)
slug: why
url: /static/pages/why.html
url: "{{static_url}}/pages/why.html"

- title: _(Features)
slug: features
url: /static/pages/features.html
url: "{{static_url}}/pages/features.html"

- title: _(Links)
pages:
Expand Down
9 changes: 8 additions & 1 deletion src/project/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,13 @@
# If you set this to False, Django will not use timezone-aware datetimes.
USE_TZ = True

# Path or URL prefix for all app paths and static files. This is useful if you
# want to run Shareabouts under a subpath, such as `/subpath/`. Note that if the
# `BASE_URL` is set, the site will not work directly through runserver, so you
# should use a reverse proxy in front of it. Thus by default, this is an empty
# string.
BASE_URL = os.environ.get('BASE_URL', '')

# Absolute filesystem path to the directory that will hold user-uploaded files.
# Example: "/home/media/media.lawrence.com/media/"
MEDIA_ROOT = ''
Expand All @@ -79,7 +86,7 @@

# URL prefix for static files.
# Example: "http://media.lawrence.com/static/"
STATIC_URL = '/static/'
STATIC_URL = BASE_URL + '/static/'
COMPRESS_URL = STATIC_URL

# Additional locations of static files
Expand Down
17 changes: 12 additions & 5 deletions src/project/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,24 @@
from django.contrib import admin
from django.views.i18n import set_language

from urllib.parse import urlparse
base_url = urlparse(settings.BASE_URL)
if base_url.path:
base_path = base_url.path.strip('/') + '/'
else:
base_path = ''


admin.autodiscover()

urlpatterns = [
path('choose-language', set_language, name='set_language'),
path('login/', include('sa_login.urls')),
path('admin/', include('sa_admin.urls')),
path('', include('sa_web.urls')),
path(base_path + 'choose-language', set_language, name='set_language'),
path(base_path + 'login/', include('sa_login.urls')),
path(base_path + 'admin/', include('sa_admin.urls')),
path(base_path + '', include('sa_web.urls')),
]

if settings.SHAREABOUTS['DATASET_ROOT'].startswith('/'):
urlpatterns = [
path('full-api/', include('sa_api_v2.urls')),
path(base_path + 'full-api/', include('sa_api_v2.urls')),
] + urlpatterns
7 changes: 5 additions & 2 deletions src/sa_admin/templates/sa_admin/base.html
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,6 @@ <h1>{% block heading %}Shareabouts Admin{% endblock %}</h1>
<script src="{% static 'dist/libs.min.js' %}?_={{settings.LAST_DEPLOY_DATE}}"></script>
{% endif %}

<script src="{% static 'js/models.js' %}"></script>

<script>
var Shareabouts = Shareabouts || {};
Shareabouts.Config = {{ config.data | as_json | safe }};
Expand All @@ -77,9 +75,14 @@ <h1>{% block heading %}Shareabouts Admin{% endblock %}</h1>
dataset: {{ api.dataset_root | as_json | safe }},
staticUrl: {{ STATIC_URL | as_json | safe }},
mapboxToken: {{ settings.MAPBOX_TOKEN | as_json | safe }},
routePrefix: {{ route_prefix | as_json }},
apiPrefix: {{ api_prefix | as_json }},
};

Shareabouts.PlaceCollection.prototype.url += '?include_private&include_invisible';
</script>

<script src="{% static 'js/utils.js' %}"></script>
<script src="{% static 'js/models.js' %}"></script>
{% endblock %}
</html>
9 changes: 9 additions & 0 deletions src/sa_admin/views.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from django.conf import settings
from django.shortcuts import render, redirect
from django.urls import reverse
from sa_util.config import get_shareabouts_config
Expand All @@ -20,15 +21,23 @@ def wrapper(request, *args, **kwargs):

@shareabouts_loggedin
def admin_home(request, config, api):
path_prefix = settings.BASE_URL

return render(request, 'sa_admin/dashboard.html', {
'route_prefix': path_prefix,
'api_prefix': path_prefix + '/api',
'api': api,
'config': config,
})


@shareabouts_loggedin
def place_detail(request, config, api, place_id):
path_prefix = settings.BASE_URL

return render(request, 'sa_admin/place_detail.html', {
'route_prefix': path_prefix,
'api_prefix': path_prefix + '/api',
'place_id': place_id,
'api': api,
'config': config,
Expand Down
12 changes: 12 additions & 0 deletions src/sa_util/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,19 @@


def make_api_root(dataset_root):
"""
Construct the API root URL based on the dataset root.

If we're hitting an API server (as opposed to using a file backend), then
the dataset_root should be a URL of the form:
<api_root>/<dataset_owner>/datasets/<dataset_name>/

Thus the API root should be everything before the dataset owner.
"""
components = dataset_root.split('/')
if dataset_root.startswith('http') and (components[-2] != 'datasets' and components[-3] != 'datasets'):
raise ValueError(f'dataset_root expected to be a URL of the form http[s]://<api_root>/<dataset_owner>/datasets/<dataset_name>/; got {dataset_root!r}')

if dataset_root.endswith('/'):
return '/'.join(components[:-4]) + '/'
else:
Expand Down
21 changes: 20 additions & 1 deletion src/sa_util/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,16 +78,32 @@ def parse_msg(s):
return s[2:-1]


def interpolate(data):
"""
Interpolate strings in the data structure that contain placeholders.
Placeholders are of the form {key} where key is a key in the data structure.
"""
if isinstance(data, dict):
return {k: interpolate(v) for k, v in data.items()}
elif isinstance(data, list):
return [interpolate(item) for item in data]
elif isinstance(data, str):
return data.replace('{{static_url}}', settings.STATIC_URL)
else:
return data


class _ShareaboutsConfig:
"""
Base class representing Shareabouts configuration options
"""
raw = False
apply_env = True

def __init__(self, translate=True, apply_env=True):
def __init__(self, translate=True, apply_env=True, interpolate=True):
self.translate = translate
self.apply_env = apply_env
self.interpolate = interpolate

@property
def data(self):
Expand All @@ -100,6 +116,9 @@ def data(self):

if self.translate:
self._data = translate(self._data)

if self.interpolate:
self._data = interpolate(self._data)

return self._data

Expand Down
2 changes: 1 addition & 1 deletion src/sa_web/jstemplates/activity-list-item.html
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<li class="activity-item clearfix">
{{!-- data attributes are not ideal, see comment in activity view --}}
<a href="/place/{{ place.id }}{{#is target_type 'comments'}}/response/{{ target.id }}{{/is}}" data-action-type="{{ target_type }}" data-place-id="{{ place.id }}">{{#_}}<strong>
<a href="{{ prefix "/place/" }}{{ place.id }}{{#is target_type 'comments'}}/response/{{ target.id }}{{/is}}" data-action-type="{{ target_type }}" data-place-id="{{ place.id }}">{{#_}}<strong>

{{#if target.submitter}}
<img src="{{ target.submitter.avatar_url }}" role="presentation" alt="" class="avatar" /> {{ target.submitter.name }}
Expand Down
6 changes: 3 additions & 3 deletions src/sa_web/jstemplates/auth-nav.html
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,16 @@
{{#with (current_user "name") }}
<li><span class="signed-in-as">{{#_}}Signed in as</span> <span class="current-user">{{ this }}{{/_}}</span></li>
{{/with}}
<li class=""><a class="logout-btn" href="/users/logout/">{{#_}}Log Out{{/_}}</a>
<li class=""><a class="logout-btn" href="{{prefix "/users/"}}logout/">{{#_}}Log Out{{/_}}</a>
</li>
</ul>
</nav>
{{ else }}
<nav class="user-menu" aria-label="User account">
<a href="#" id="sign-in-btn">{{#_}}Sign In{{/_}}</a>
<ul class="menu sign-in-menu">
<li class="menu-item sign-in-menu-item"><a class="auth-btn twitter-btn" href="/users/login/twitter/">Twitter</a></li>
<li class="menu-item sign-in-menu-item"><a class="auth-btn facebook-btn" href="/users/login/facebook/">Facebook</a></li>
<li class="menu-item sign-in-menu-item"><a class="auth-btn twitter-btn" href="{{prefix "/users/"}}login/twitter/">Twitter</a></li>
<li class="menu-item sign-in-menu-item"><a class="auth-btn facebook-btn" href="{{prefix "/users/"}}login/facebook/">Facebook</a></li>
</ul>
</nav>
{{/ is_authenticated }}
2 changes: 1 addition & 1 deletion src/sa_web/jstemplates/form-field-input.html
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{{#is_submitter_name}}
{{^is_authenticated}}
<input id="{{ default submission_type 'place' }}-{{ name }}" name="{{ name }}" type="{{ type }}" {{#attrs}} {{ key }}="{{ value }}"{{/attrs}} value="{{get_value ../../form_config name}}">
<span class="or-sign-in">{{#_}}Or sign in with <a class="auth-inline twitter-btn" href="/users/login/twitter/">Twitter</a> <a class="auth-inline facebook-btn" href="/users/login/facebook/">Facebook</a>{{/_}}</span>
<span class="or-sign-in">{{#_}}Or sign in with <a class="auth-inline twitter-btn" href="{{prefix "/users/"}}login/twitter/">Twitter</a> <a class="auth-inline facebook-btn" href="{{prefix "/users/"}}login/facebook/">Facebook</a>{{/_}}</span>
{{/is_authenticated}}
{{^}}
<input id="{{ default submission_type 'place' }}-{{ name }}" name="{{ name }}" type="{{ type }}" {{#attrs}} {{ key }}="{{ value }}"{{/attrs}} value="{{get_value ../form_config name}}">
Expand Down
2 changes: 1 addition & 1 deletion src/sa_web/jstemplates/page-nav-item.html
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

{{^ external }}
{{# slug }}
<a class="btn btn-block btn-secondary" href="/page/{{ slug }}">{{ title }}</a>
<a class="btn btn-block btn-secondary" href="{{prefix "/page/"}}{{ slug }}">{{ title }}</a>
{{/ slug }}
{{^ slug }}
{{ title }}
Expand Down
2 changes: 1 addition & 1 deletion src/sa_web/jstemplates/pages-nav-item.html
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
<a class="btn btn-block btn-secondary" href="{{ url }}" {{#each link_attrs}} {{@key}}="{{this}}" {{/each}}>{{ title }}</a>
{{else }}
{{#if slug }}
<a class="btn btn-block btn-secondary" href="/page/{{ slug }}" {{#each link_attrs}} {{@key}}="{{this}}" {{/each}}>{{ title }}</a>
<a class="btn btn-block btn-secondary" href="{{prefix "/page/"}}{{ slug }}" {{#each link_attrs}} {{@key}}="{{this}}" {{/each}}>{{ title }}</a>
{{else }}
<a class="btn btn-block btn-secondary" {{#each link_attrs}} {{@key}}="{{this}}" {{/each}}>{{ title }}</a>
{{/if }}
Expand Down
4 changes: 2 additions & 2 deletions src/sa_web/jstemplates/place-detail.html
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,12 @@ <h1>{{#if name }}{{ name }}{{^}}{{>location-string .}}{{/if}}</h1>
in {{ region }}
{{/if}}{{/_}}

<time datetime="{{ created_datetime }}" class="response-date"><a href="/place/{{ id }}">{{ fromnow created_datetime }}</a></time>
<time datetime="{{ created_datetime }}" class="response-date"><a href="{{prefix "/place/"}}{{ id }}">{{ fromnow created_datetime }}</a></time>

<span class="survey-count">{{ survey_count }} {{ survey_label_by_count }}</span>

{{^if survey_config}}
<a href="/place/{{ id }}" class="view-on-map-btn btn btn-small">{{#_}}View On Map{{/_}}</a>
<a href="{{prefix "/place/"}}{{ id }}" class="view-on-map-btn btn btn-small">{{#_}}View On Map{{/_}}</a>
{{/if}}

</span>
Expand Down
4 changes: 4 additions & 0 deletions src/sa_web/static/js/handlebars-helpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ var Shareabouts = Shareabouts || {};
return NS.bootstrapped.staticUrl;
});

Handlebars.registerHelper('prefix', function(route) {
return NS.Util.prefixRoute(route);
});

Handlebars.registerHelper('debug', function(value) {
if (typeof(value) === typeof({})) {
return JSON.stringify(value, null, 4);
Expand Down
6 changes: 3 additions & 3 deletions src/sa_web/static/js/models.js
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ var Shareabouts = Shareabouts || {};
'must save the place before saving ' +
'its ' + submissionType + '.'); }

return '/api/places/' + placeId + '/' + submissionType;
return S.Util.prefixApiEndpoint('/places/' + placeId + '/' + submissionType);
},

comparator: 'created_datetime'
Expand Down Expand Up @@ -250,7 +250,7 @@ var Shareabouts = Shareabouts || {};
});

S.PlaceCollection = S.PaginatedCollection.extend({
url: '/api/places',
url: S.Util.prefixApiEndpoint('/places'),
model: S.PlaceModel,
resultsAttr: 'features',

Expand Down Expand Up @@ -375,7 +375,7 @@ var Shareabouts = Shareabouts || {};
});

S.ActionCollection = S.PaginatedCollection.extend({
url: '/api/actions',
url: S.Util.prefixApiEndpoint('/actions'),
comparator: function(a, b) {
if (a.get('created_datetime') > b.get('created_datetime')) {
return -1;
Expand Down
3 changes: 3 additions & 0 deletions src/sa_web/static/js/routes.js
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,9 @@ var Shareabouts = Shareabouts || {};
if (options.defaultPlaceTypeName) {
historyOptions.root = '/' + options.defaultPlaceTypeName + '/';
}
if (options.routePrefix) {
historyOptions.root = options.routePrefix + '/';
}

Backbone.history.start(historyOptions);

Expand Down
Loading