Skip to content

Commit cb7c5dc

Browse files
committed
Merge branch 'release/0.124.0'
2 parents 29f5194 + 56e601a commit cb7c5dc

File tree

148 files changed

+2521
-352
lines changed

Some content is hidden

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

148 files changed

+2521
-352
lines changed

.docker-compose.sharejs.env

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
SHAREJS_SERVER_HOST=0.0.0.0
22
SHAREJS_SERVER_PORT=7007
33
SHAREJS_DB_NAME=sharejs
4-
SHAREJS_DB_URL=mongodb://192.168.168.167:27017/sharejs
4+
SHAREJS_DB_URL=mongodb://192.168.168.167:27017/sharejs?ssl=true
55

66
#SHAREJS_CORS_ALLOW_ORIGIN=
77
#SHAREJS_SENTRY_DSN=

.dockerignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,4 @@ node_modules
77
*.pyc
88
**/*.pyc
99
docker*
10+
ssl/

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,3 +194,4 @@ scripts/image_maniplation/test_rounded_corners.html
194194
docker-compose.override.yml
195195
.unison*
196196
.docker-sync/
197+
ssl/

CHANGELOG

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,11 @@
22
Changelog
33
*********
44

5+
0.124.0 (2017-11-13)
6+
====================
7+
8+
- Critical bug fixes
9+
510
0.123.0 (2017-10-26)
611
====================
712

Dockerfile

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,14 @@ ENV GOSU_VERSION=1.10 \
66
YARN_VERSION=1.1.0
77

88
# Libraries such as matplotlib require a HOME directory for cache and configuration
9-
RUN usermod -d /home www-data \
10-
&& chown www-data:www-data /home \
11-
# https://github.com/nodejs/docker-node/blob/9c25cbe93f9108fd1e506d14228afe4a3d04108f/8.2/Dockerfile
12-
# gpg keys listed at https://github.com/nodejs/node#release-team
13-
&& set -ex \
9+
RUN set -ex \
10+
&& mkdir -p /var/www \
11+
&& chown www-data:www-data /var/www \
1412
# GOSU
1513
&& gpg --keyserver pool.sks-keyservers.net --recv-keys B42F6819007F00F88E364FD4036A9C25BF357DD4 \
1614
&& for key in \
15+
# https://github.com/nodejs/docker-node/blob/9c25cbe93f9108fd1e506d14228afe4a3d04108f/8.2/Dockerfile
16+
# gpg keys listed at https://github.com/nodejs/node#release-team
1717
# Node
1818
9554F04D7259F04124DE6B476D5A82AC7E37093B \
1919
94AE36675C464D64BAFA68DD7434390BDBE9B9C5 \

README-docker-compose.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ Ubuntu: Skip install of docker-sync. instead...
120120
_NOTE: When the various requirements installations are complete these containers will exit. You should only need to run these containers after pulling code that changes python requirements or if you update the python requirements._
121121

122122
2. Start Core Component Services (Detached)
123-
- `$ docker-compose up -d elasticsearch postgres tokumx rabbitmq`
123+
- `$ docker-compose up -d elasticsearch postgres mongo rabbitmq`
124124

125125
3. Remove your existing node_modules and start the assets watcher (Detached)
126126
- `$ rm -Rf ./node_modules`

addons/wiki/settings/defaults.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import datetime
2-
2+
import os
33
import pytz
44

55
from website import settings
@@ -9,7 +9,7 @@
99
SHAREJS_URL = '{}:{}'.format(SHAREJS_HOST, SHAREJS_PORT)
1010

1111
SHAREJS_DB_NAME = 'sharejs'
12-
SHAREJS_DB_URL = 'mongodb://{}:{}/{}'.format(settings.DB_HOST, settings.DB_PORT, SHAREJS_DB_NAME)
12+
SHAREJS_DB_URL = os.environ.get('SHAREJS_DB_URL', 'mongodb://{}:{}/{}'.format(settings.DB_HOST, settings.DB_PORT, SHAREJS_DB_NAME))
1313

1414
# TODO: Change to release date for wiki change
1515
WIKI_CHANGE_DATE = datetime.datetime.utcfromtimestamp(1423760098).replace(tzinfo=pytz.utc)

addons/wiki/utils.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import urllib
44
import uuid
55

6+
import ssl
67
from pymongo import MongoClient
78
import requests
89

@@ -101,7 +102,7 @@ def migrate_uuid(node, wname):
101102

102103
def share_db():
103104
"""Generate db client for sharejs db"""
104-
client = MongoClient(wiki_settings.SHAREJS_DB_URL)
105+
client = MongoClient(wiki_settings.SHAREJS_DB_URL, ssl_cert_reqs=ssl.CERT_NONE)
105106
return client[wiki_settings.SHAREJS_DB_NAME]
106107

107108

admin/preprint_providers/views.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
from django.core.urlresolvers import reverse_lazy
77
from django.http import HttpResponse, JsonResponse
88
from django.views.generic import ListView, DetailView, View, CreateView, DeleteView, TemplateView, UpdateView
9+
from django.core.management import call_command
910
from django.contrib.auth.mixins import PermissionRequiredMixin
1011
from django.forms.models import model_to_dict
1112
from django.shortcuts import redirect
@@ -18,8 +19,7 @@
1819

1920
# When preprint_providers exclusively use Subject relations for creation, set this to False
2021
SHOW_TAXONOMIES_IN_PREPRINT_PROVIDER_CREATE = True
21-
#TODO: Add subjects back in when custom taxonomies are fully integrated
22-
FIELDS_TO_NOT_IMPORT_EXPORT = ['access_token', 'share_source', 'subjects_acceptable', 'subjects']
22+
FIELDS_TO_NOT_IMPORT_EXPORT = ['access_token', 'share_source']
2323

2424

2525
class PreprintProviderList(PermissionRequiredMixin, ListView):
@@ -170,15 +170,15 @@ def get(self, request, *args, **kwargs):
170170
cleaned_fields = {key: value for key, value in cleaned_data['fields'].iteritems() if key not in FIELDS_TO_NOT_IMPORT_EXPORT}
171171
cleaned_fields['licenses_acceptable'] = [node_license.license_id for node_license in preprint_provider.licenses_acceptable.all()]
172172
cleaned_fields['default_license'] = preprint_provider.default_license.license_id if preprint_provider.default_license else ''
173-
# cleaned_fields['subjects'] = self.serialize_subjects(preprint_provider)
173+
cleaned_fields['subjects'] = self.serialize_subjects(preprint_provider)
174174
cleaned_data['fields'] = cleaned_fields
175175
filename = '{}_export.json'.format(preprint_provider.name)
176176
response = HttpResponse(json.dumps(cleaned_data), content_type='text/json')
177177
response['Content-Disposition'] = 'attachment; filename={}'.format(filename)
178178
return response
179179

180180
def serialize_subjects(self, provider):
181-
if provider._id != 'osf':
181+
if provider._id != 'osf' and provider.subjects.count():
182182
result = {}
183183
result['include'] = []
184184
result['exclude'] = []
@@ -231,8 +231,9 @@ def post(self, request, *args, **kwargs):
231231
if form.is_valid():
232232
file_str = self.parse_file(request.FILES['file'])
233233
file_json = json.loads(file_str)
234+
current_fields = [f.name for f in PreprintProvider._meta.get_fields()]
234235
# make sure not to import an exported access token for SHARE
235-
cleaned_result = {key: value for key, value in file_json['fields'].iteritems() if key not in FIELDS_TO_NOT_IMPORT_EXPORT}
236+
cleaned_result = {key: value for key, value in file_json['fields'].iteritems() if key not in FIELDS_TO_NOT_IMPORT_EXPORT and key in current_fields}
236237
preprint_provider = self.create_or_update_provider(cleaned_result)
237238
return redirect('preprint_providers:detail', preprint_provider_id=preprint_provider.id)
238239

@@ -248,8 +249,7 @@ def get_page_provider(self):
248249
return PreprintProvider.objects.get(id=page_provider_id)
249250

250251
def add_subjects(self, provider, subject_data):
251-
from osf.management.commands.populate_custom_taxonomies import migrate
252-
migrate(provider._id, subject_data)
252+
call_command('populate_custom_taxonomies', '--provider', provider._id, '--data', json.dumps(subject_data))
253253

254254
def create_or_update_provider(self, provider_data):
255255
provider = self.get_page_provider()

admin/static/js/metrics/metrics.es6.js

Lines changed: 81 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,31 @@ var getOneDayTimeframe = function(daysBack, monthsBack) {
6464
};
6565
};
6666

67+
/**
68+
* Configure a time frame for a day x days ago (end) and y days prior to x (start)
69+
*
70+
* @method getVariableDayTimeframe
71+
* @param {Integer} endDaysBack - the number of days back to set as the end day
72+
* @param {Integer} totalDays - the number of days back to reach the start day
73+
* @return {Object} the keen-formatted timeframe
74+
*/
75+
var getVariableDayTimeframe = function(endDaysBack, totalDays) {
76+
var start = null;
77+
var end = null;
78+
var date = new Date();
6779

80+
date.setUTCDate(date.getDate() - endDaysBack);
81+
date.setUTCHours(0, 0, 0, 0, 0);
82+
83+
end = date.toISOString();
84+
85+
date.setDate(date.getDate() - totalDays);
86+
start = date.toISOString();
87+
return {
88+
"start": start,
89+
"end": end
90+
};
91+
};
6892

6993
/**
7094
* Configure a Title for a chart dealing with the past month or day
@@ -322,6 +346,14 @@ var monthlyActiveUsersQuery = new keenAnalysis.Query("count_unique", {
322346
timezone: "UTC"
323347
});
324348

349+
// Previous 30 Days Active Users
350+
var thirtyDaysActiveUsersQuery = new keenAnalysis.Query("count_unique", {
351+
eventCollection: "pageviews",
352+
targetProperty: "user.id",
353+
timeframe: "previous_30_days",
354+
timezone: "UTC"
355+
});
356+
325357
var dailyActiveUsersQuery = new keenAnalysis.Query("count_unique", {
326358
event_collection: "pageviews",
327359
target_property: "user.id",
@@ -336,6 +368,48 @@ var totalProjectsQuery = new keenAnalysis.Query("sum", {
336368
timeframe: "previous_1_days",
337369
});
338370

371+
// 7 Days back Active Users
372+
var weekBackThirtyDaysActiveUsersQuery = new keenAnalysis.Query("count_unique", {
373+
eventCollection: "pageviews",
374+
targetProperty: "user.id",
375+
timeframe: getVariableDayTimeframe(7, 30),
376+
});
377+
378+
// 7 Days back Active Users
379+
var weekBackDailyActiveUsersQuery = new keenAnalysis.Query("count_unique", {
380+
eventCollection: "pageviews",
381+
targetProperty: "user.id",
382+
timeframe: getVariableDayTimeframe(7, 1),
383+
});
384+
385+
// 28 Days back Active Users
386+
var monthBackThirtyDaysActiveUsersQuery = new keenAnalysis.Query("count_unique", {
387+
eventCollection: "pageviews",
388+
targetProperty: "user.id",
389+
timeframe: getVariableDayTimeframe(28, 30),
390+
});
391+
392+
// 28 Days back Active Users
393+
var monthBackDailyActiveUsersQuery = new keenAnalysis.Query("count_unique", {
394+
eventCollection: "pageviews",
395+
targetProperty: "user.id",
396+
timeframe: getVariableDayTimeframe(28, 1),
397+
});
398+
399+
// 364 Days back Active Users
400+
var yearBackThirtyDaysActiveUsersQuery = new keenAnalysis.Query("count_unique", {
401+
eventCollection: "pageviews",
402+
targetProperty: "user.id",
403+
timeframe: getVariableDayTimeframe(364, 30),
404+
});
405+
406+
// 364 Days back Active Users
407+
var yearBackDailyActiveUsersQuery = new keenAnalysis.Query("count_unique", {
408+
eventCollection: "pageviews",
409+
targetProperty: "user.id",
410+
timeframe: getVariableDayTimeframe(364, 1),
411+
});
412+
339413
// <+><+><+><+><+><+
340414
// user data |
341415
// ><+><+><+><+><+>+
@@ -808,7 +882,13 @@ var ActiveUserMetrics = function() {
808882
var HealthyUserMetrics = function() {
809883

810884
// stickiness ratio - DAU/MAU
811-
renderCalculationBetweenTwoQueries(dailyActiveUsersQuery, monthlyActiveUsersQuery, "#stickiness-ratio", null, "percentage");
885+
renderCalculationBetweenTwoQueries(dailyActiveUsersQuery, thirtyDaysActiveUsersQuery, "#stickiness-ratio-1-day-ago", null, "percentage");
886+
// stickiness ratio - DAU/MAU for 1 week ago
887+
renderCalculationBetweenTwoQueries(weekBackDailyActiveUsersQuery, weekBackThirtyDaysActiveUsersQuery , "#stickiness-ratio-1-week-ago", null, "percentage");
888+
// stickiness ratio - DAU/MAU for 4 weeks ago
889+
renderCalculationBetweenTwoQueries(monthBackDailyActiveUsersQuery, monthBackThirtyDaysActiveUsersQuery , "#stickiness-ratio-4-weeks-ago", null, "percentage");
890+
// stickiness ratio - DAU/MAU for 52 weeks ago
891+
renderCalculationBetweenTwoQueries(yearBackDailyActiveUsersQuery, yearBackThirtyDaysActiveUsersQuery , "#stickiness-ratio-52-weeks-ago", null, "percentage");
812892
};
813893

814894

admin/templates/metrics/osf_metrics.html

Lines changed: 42 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -577,10 +577,50 @@ <h4>Project to User Ratios</h4>
577577
Stickiness Ratio
578578
</div>
579579
<div class="chart-stage">
580-
<div id="stickiness-ratio"></div>
580+
<div id="stickiness-ratio-1-day-ago"></div>
581581
</div>
582582
<div class="chart-notes">
583-
Of those that are active in the last month, how many are active daily? Daily Active Users / Monthly Active Users.
583+
Of those that are active in the last 30 days, how many are active daily?
584+
Formula: Daily Active Users (yesterday) / Daily Active Users previous 30 days
585+
</div>
586+
</div>
587+
</div>
588+
<div class="col-sm-4">
589+
<div class="chart-wrapper">
590+
<div class="chart-title">
591+
Stickiness Ratio 1 week ago
592+
</div>
593+
<div class="chart-stage">
594+
<div id="stickiness-ratio-1-week-ago"></div>
595+
</div>
596+
<div class="chart-notes">
597+
Stickiness Ratio for the same day of the week 1 week ago.
598+
</div>
599+
</div>
600+
</div>
601+
<div class="col-sm-4">
602+
<div class="chart-wrapper">
603+
<div class="chart-title">
604+
Stickiness Ratio 4 weeks ago
605+
</div>
606+
<div class="chart-stage">
607+
<div id="stickiness-ratio-4-weeks-ago"></div>
608+
</div>
609+
<div class="chart-notes">
610+
Stickiness Ratio for the same day of the week 4 weeks ago.
611+
</div>
612+
</div>
613+
</div>
614+
<div class="col-sm-4">
615+
<div class="chart-wrapper">
616+
<div class="chart-title">
617+
Stickiness Ratio 52 weeks ago
618+
</div>
619+
<div class="chart-stage">
620+
<div id="stickiness-ratio-52-weeks-ago"></div>
621+
</div>
622+
<div class="chart-notes">
623+
Stickiness Ratio for the same day of the week 52 weeks ago.
584624
</div>
585625
</div>
586626
</div>

admin_tests/preprint_providers/test_views.py

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -250,11 +250,32 @@ def test_export_to_import_new_provider(self):
250250

251251
nt.assert_equal(res.status_code, 302)
252252
nt.assert_equal(new_provider._id, 'new_id')
253-
# nt.assert_equal(new_provider.subjects.all().count(), 1)
253+
nt.assert_equal(new_provider.subjects.all().count(), 1)
254254
nt.assert_equal(new_provider.licenses_acceptable.all().count(), 1)
255-
# nt.assert_equal(new_provider.subjects.all()[0].text, self.subject.text)
255+
nt.assert_equal(new_provider.subjects.all()[0].text, self.subject.text)
256256
nt.assert_equal(new_provider.licenses_acceptable.all()[0].license_id, 'NONE')
257257

258+
def test_export_to_import_new_provider_with_models_out_of_sync(self):
259+
update_taxonomies('test_bepress_taxonomy.json')
260+
261+
res = self.view.get(self.request)
262+
content_dict = json.loads(res.content)
263+
264+
content_dict['fields']['_id'] = 'new_id'
265+
content_dict['fields']['new_field'] = 'this is a new field, not in the model'
266+
del content_dict['fields']['description'] # this is a old field, removed from the model JSON
267+
268+
data = StringIO(unicode(json.dumps(content_dict), 'utf-8'))
269+
self.import_request.FILES['file'] = InMemoryUploadedFile(data, None, 'data', 'application/json', 500, None, {})
270+
271+
res = self.import_view.post(self.import_request)
272+
273+
provider_id = ''.join([i for i in res.url if i.isdigit()])
274+
new_provider = PreprintProvider.objects.get(id=provider_id)
275+
276+
nt.assert_equal(res.status_code, 302)
277+
nt.assert_equal(new_provider._id, 'new_id')
278+
258279
def test_update_provider_existing_subjects(self):
259280
# If there are existing subjects for a provider, imported subjects are ignored
260281
self.import_view.kwargs = {'preprint_provider_id': self.preprint_provider.id}
@@ -281,9 +302,9 @@ def test_update_provider_existing_subjects(self):
281302

282303
nt.assert_equal(res.status_code, 302)
283304
nt.assert_equal(new_provider_id, self.preprint_provider.id)
284-
# nt.assert_equal(self.preprint_provider.subjects.all().count(), 1)
305+
nt.assert_equal(self.preprint_provider.subjects.all().count(), 1)
285306
nt.assert_equal(self.preprint_provider.licenses_acceptable.all().count(), 1)
286-
# nt.assert_equal(self.preprint_provider.subjects.all()[0].text, self.subject.text)
307+
nt.assert_equal(self.preprint_provider.subjects.all()[0].text, self.subject.text)
287308
nt.assert_equal(self.preprint_provider.licenses_acceptable.all()[0].license_id, 'CCBY')
288309

289310

api/base/generic_bulk_views.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ def get_requested_resources(self, request, request_data):
7676
Retrieves resources in request body
7777
"""
7878
model_cls = request.parser_context['view'].model_class
79+
7980
requested_ids = [data['id'] for data in request_data]
8081
column_name = 'guids___id' if issubclass(model_cls, GuidMixin) else '_id'
8182
resource_object_list = model_cls.find(Q(column_name, 'in', requested_ids))
@@ -87,6 +88,11 @@ def get_requested_resources(self, request, request_data):
8788
if len(resource_object_list) != len(request_data):
8889
raise ValidationError({'non_field_errors': 'Could not find all objects to delete.'})
8990

91+
if column_name == 'guids___id':
92+
resource_object_list = [resource_object_list.get(guids___id=id) for id in requested_ids]
93+
else:
94+
resource_object_list = [resource_object_list.get(_id=id) for id in requested_ids]
95+
9096
return resource_object_list
9197

9298
def allow_bulk_destroy_resources(self, user, resource_list):

0 commit comments

Comments
 (0)