Skip to content

Commit 3133bb9

Browse files
authored
Merge pull request #1554 from Scifabric/issue-1553
Issue 1553
2 parents b975dbf + 1daccfc commit 3133bb9

Some content is hidden

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

58 files changed

+782
-55
lines changed

doc/customizing.rst

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -695,6 +695,39 @@ To:
695695
This feature is disabled by default.
696696

697697

698+
Making extra key/value pairs in info field public
699+
=================================================
700+
701+
By default PYBOSSA protects all the information the info field except for those
702+
values that are public like the url of the image of the project, the container
703+
where that picture is stored and a few extra. While this will be more than enough
704+
for most projects, sometimes, a server will need to expose more information publicly
705+
via the info field for the User and Project Domain Objects.
706+
707+
Imagine that you want to give badges to users. You can store that information in the
708+
User domain object, within the info field in a field named *badges*. While this will
709+
work, the API will hide all that information except for the owner. Thus, it will be impossible
710+
to show user's badges to anonymous people.
711+
712+
With projects it could be the same. You want to highlight some info to anyone, but hide everything else.
713+
714+
As PYBOSSA hides everything by default, you can always turn on which other fields from the
715+
info field can be shown to anonymous users, making them public.
716+
717+
.. note::
718+
719+
WARNING: be very careful. This is your responsibility, and it's not enabled by default. If you
720+
expose your own private data via this field, it's your own responsibility as this is not enabled
721+
by default in PYBOSSA.
722+
723+
If you want to make some key/values public, all you have to do is add to the settings_local.py file
724+
the following config variables::
725+
726+
PROJECT_INFO_PUBLIC_FIELDS = ['key1', 'key2']
727+
USER_INFO_PUBLIC_FIELDS = ['badges', 'key2', ...]
728+
729+
Add as many as you want, need. But please, be careful about which information you disclose.
730+
698731
Adding your own templates
699732
=========================
700733

pybossa/extensions.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@
3232
* csrf: for CSRF protection
3333
* newsletter: for subscribing users to Mailchimp newsletter
3434
* assets: for assets management (SASS, etc.)
35+
* JSONEncoder: a custom JSON encoder to handle specific types
36+
* cors: the Flask-Cors library object
3537
3638
"""
3739
__all__ = ['sentinel', 'db', 'signer', 'mail', 'login_manager', 'facebook',

pybossa/model/project.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
from sqlalchemy.orm import relationship, backref
2222
from sqlalchemy.dialects.postgresql import JSON
2323
from sqlalchemy.ext.mutable import MutableDict
24+
from flask import current_app
2425

2526
from pybossa.core import db, signer
2627
from pybossa.model import DomainObject, make_timestamp, make_uuid
@@ -126,5 +127,10 @@ def public_attributes(self):
126127
@classmethod
127128
def public_info_keys(self):
128129
"""Return a list of public info keys."""
129-
return ['container', 'thumbnail', 'thumbnail_url',
130-
'task_presenter', 'tutorial', 'sched']
130+
default = ['container', 'thumbnail', 'thumbnail_url',
131+
'task_presenter', 'tutorial', 'sched']
132+
extra = current_app.config.get('PROJECT_INFO_PUBLIC_FIELDS')
133+
if extra:
134+
return list(set(default).union(set(extra)))
135+
else:
136+
return default

pybossa/model/user.py

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,12 @@
1717
# along with PYBOSSA. If not, see <http://www.gnu.org/licenses/>.
1818

1919
from sqlalchemy import Integer, Boolean, Unicode, Text, String, BigInteger
20-
from sqlalchemy.schema import Column, ForeignKey
21-
from sqlalchemy.orm import relationship, backref
20+
from sqlalchemy.schema import Column
21+
from sqlalchemy.orm import relationship
2222
from sqlalchemy.dialects.postgresql import JSON
2323
from sqlalchemy.ext.mutable import MutableDict
2424
from flask.ext.login import UserMixin
25+
from flask import current_app
2526

2627
from pybossa.core import db, signer
2728
from pybossa.model import DomainObject, make_timestamp, make_uuid
@@ -92,4 +93,9 @@ def public_attributes(self):
9293
@classmethod
9394
def public_info_keys(self):
9495
"""Return a list of public info keys."""
95-
return ['avatar', 'container', 'extra', 'avatar_url']
96+
default = ['avatar', 'container', 'extra', 'avatar_url']
97+
extra = current_app.config.get('USER_INFO_PUBLIC_FIELDS')
98+
if extra:
99+
return list(set(default).union(set(extra)))
100+
else:
101+
return default

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@
6262

6363
setup(
6464
name = 'pybossa',
65-
version = '2.4.1',
65+
version = '2.4.2',
6666
packages = find_packages(),
6767
install_requires = requirements,
6868
# only needed when installing directly from setup.py (PyPi, eggs?) and pointing to e.g. a git repo.

test/test_api/test_api_common.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -292,7 +292,7 @@ def test_query_sql_injection(self):
292292
res = self.app.get('/api' + q)
293293
assert res.status_code == 404, res.data
294294

295-
295+
@with_context
296296
def test_jsonpify(self):
297297
"""Test API jsonpify decorator works."""
298298
project = ProjectFactory.create()

test/test_api/test_disqus_sso_api.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323

2424
class TestDisqusSSO(TestAPI):
2525

26+
@with_context
2627
def test_auth(self):
2728
"""Test with user authenticated."""
2829
url = 'api/disqus/sso'
@@ -41,6 +42,7 @@ def test_auth(self):
4142
assert data['remote_auth_s3'] is not None, data
4243
assert data['api_key'] is not None, data
4344

45+
@with_context
4446
def test_anon(self):
4547
"""Test with user authenticated."""
4648
url = 'api/disqus/sso'
@@ -58,6 +60,7 @@ def test_anon(self):
5860
assert data['remote_auth_s3'] is not None, data
5961
assert data['api_key'] is not None, data
6062

63+
@with_context
6164
def test_auth_no_keys(self):
6265
"""Test with user authenticated."""
6366
url = 'api/disqus/sso'
@@ -70,6 +73,7 @@ def test_auth_no_keys(self):
7073
assert data['status'] == 'failed', data
7174
assert data['exception_msg'] == 'Disqus keys are missing'
7275

76+
@with_context
7377
def test_anon_no_keys(self):
7478
"""Test with user authenticated."""
7579
url = 'api/disqus/sso'

test/test_api/test_global_stats_api.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,15 @@
1616
# You should have received a copy of the GNU Affero General Public License
1717
# along with PYBOSSA. If not, see <http://www.gnu.org/licenses/>.
1818
import json
19+
from default import with_context
1920
from test_api import TestAPI
2021
from factories import ProjectFactory
2122

2223

2324

2425
class TestGlobalStatsAPI(TestAPI):
2526

27+
@with_context
2628
def test_global_stats(self):
2729
"""Test Global Stats works."""
2830
ProjectFactory()
@@ -35,6 +37,7 @@ def test_global_stats(self):
3537
err_msg = "%s should be in stats JSON object" % k
3638
assert k in stats.keys(), err_msg
3739

40+
@with_context
3841
def test_post_global_stats(self):
3942
"""Test Global Stats Post works."""
4043
res = self.app.post('api/globalstats')

test/test_api/test_project_api.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -880,6 +880,7 @@ def test_newtask(self):
880880
res = self.app.get(url)
881881
assert res.data == '{}', res.data
882882

883+
@with_context
883884
@patch('pybossa.repositories.project_repository.uploader')
884885
def test_project_delete_deletes_zip_files(self, uploader):
885886
"""Test API project delete deletes also zip files of tasks and taskruns"""
@@ -894,6 +895,7 @@ def test_project_delete_deletes_zip_files(self, uploader):
894895
call('1_project1_task_run_csv.zip', 'user_1')]
895896
assert uploader.delete_file.call_args_list == expected
896897

898+
@with_context
897899
def test_project_post_with_reserved_fields_returns_error(self):
898900
user = UserFactory.create()
899901
CategoryFactory.create()
@@ -916,6 +918,7 @@ def test_project_post_with_reserved_fields_returns_error(self):
916918
error = json.loads(res.data)
917919
assert error['exception_msg'] == "Reserved keys in payload", error
918920

921+
@with_context
919922
def test_project_put_with_reserved_returns_error(self):
920923
user = UserFactory.create()
921924
project = ProjectFactory.create(owner=user)
@@ -929,6 +932,7 @@ def test_project_put_with_reserved_returns_error(self):
929932
error = json.loads(res.data)
930933
assert error['exception_msg'] == "Reserved keys in payload", error
931934

935+
@with_context
932936
def test_project_post_with_published_attribute_is_forbidden(self):
933937
user = UserFactory.create()
934938
data = dict(
@@ -947,6 +951,7 @@ def test_project_post_with_published_attribute_is_forbidden(self):
947951
assert res.status_code == 403, res.status_code
948952
assert error_msg == 'You cannot publish a project via the API', res.data
949953

954+
@with_context
950955
def test_project_update_with_published_attribute_is_forbidden(self):
951956
user = UserFactory.create()
952957
project = ProjectFactory.create(owner=user)
@@ -960,6 +965,7 @@ def test_project_update_with_published_attribute_is_forbidden(self):
960965
assert res.status_code == 403, res.status_code
961966
assert error_msg == 'You cannot publish a project via the API', res.data
962967

968+
@with_context
963969
def test_project_delete_with_results(self):
964970
"""Test API delete project with results cannot be deleted."""
965971
result = self.create_result()
@@ -970,6 +976,7 @@ def test_project_delete_with_results(self):
970976
res = self.app.delete(url)
971977
assert_equal(res.status, '403 FORBIDDEN', res.status)
972978

979+
@with_context
973980
def test_project_delete_with_results_var(self):
974981
"""Test API delete project with results cannot be deleted by admin."""
975982
root = UserFactory.create(admin=True)

test/test_api/test_result.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -322,6 +322,7 @@ def test_result_post(self):
322322
assert err['action'] == 'POST', err
323323
assert err['exception_cls'] == 'TypeError', err
324324

325+
@with_context
325326
def test_result_post_with_reserved_fields_returns_error(self):
326327
user = UserFactory.create()
327328
project = ProjectFactory.create(owner=user)
@@ -335,6 +336,7 @@ def test_result_post_with_reserved_fields_returns_error(self):
335336
error = json.loads(res.data)
336337
assert error['exception_msg'] == "Reserved keys in payload", error
337338

339+
@with_context
338340
def test_result_put_with_reserved_fields_returns_error(self):
339341
user = UserFactory.create()
340342
result = self.create_result(owner=user)

0 commit comments

Comments
 (0)