Skip to content

Commit

Permalink
Merge branch 'master' into remove-authz
Browse files Browse the repository at this point in the history
Conflicts:
	ckan/lib/dictization/model_dictize.py

    imports
  • Loading branch information
tobes committed Dec 18, 2012
2 parents dc2ca3f + 94bf606 commit bbff265
Show file tree
Hide file tree
Showing 7 changed files with 34 additions and 152 deletions.
4 changes: 0 additions & 4 deletions ckan/lib/app_globals.py
Expand Up @@ -172,10 +172,6 @@ def _check_uptodate(self):
self._mutex.release()

def _init(self):
self.favicon = config.get('ckan.favicon', '/images/icons/ckan.ico')
facets = config.get('search.facets', 'groups tags res_format license capacity')
self.facets = facets.split()

# process the config_details to set globals
for name, options in config_details.items():
if 'name' in options:
Expand Down
6 changes: 2 additions & 4 deletions ckan/lib/dictization/model_dictize.py
@@ -1,9 +1,7 @@
import datetime
from pylons import config
from sqlalchemy.sql import select
import datetime
import ckan.model

This comment has been minimized.

Copy link
@amercader

amercader Dec 18, 2012

Member

@tobes, @kindly Not sure how it happened or which merge was responsible for that, but this breaks master, as ckan.model is required on line 268

https://github.com/okfn/ckan/blob/master/ckan/lib/dictization/model_dictize.py#L268

import ckan.misc
import ckan.misc as misc
import ckan.logic as logic
import ckan.plugins as plugins
import ckan.lib.helpers as h
Expand Down Expand Up @@ -485,7 +483,7 @@ def package_to_api(pkg, context):
dictized['license'] = pkg.license.title if pkg.license else None
dictized['ratings_average'] = pkg.get_average_rating()
dictized['ratings_count'] = len(pkg.ratings)
dictized['notes_rendered'] = ckan.misc.MarkdownFormat().to_html(pkg.notes)
dictized['notes_rendered'] = misc.MarkdownFormat().to_html(pkg.notes)

site_url = config.get('ckan.site_url', None)
if site_url:
Expand Down
7 changes: 0 additions & 7 deletions ckan/logic/action/create.py
Expand Up @@ -104,8 +104,6 @@ def package_create(context, data_dict):
'''
model = context['model']
user = context['user']
model.Session.remove()
model.Session()._context = context

package_type = data_dict.get('type')
package_plugin = lib_plugins.lookup_package_plugin(package_type)
Expand Down Expand Up @@ -179,8 +177,6 @@ def package_create(context, data_dict):
def package_create_validate(context, data_dict):
model = context['model']
schema = lib_plugins.lookup_package_plugin().form_to_db_schema()
model.Session.remove()
model.Session()._context = context

_check_access('package_create',context,data_dict)

Expand Down Expand Up @@ -867,9 +863,6 @@ def vocabulary_create(context, data_dict):
model = context['model']
schema = context.get('schema') or ckan.logic.schema.default_create_vocabulary_schema()

model.Session.remove()
model.Session()._context = context

_check_access('vocabulary_create', context, data_dict)

data, errors = _validate(data_dict, schema, context)
Expand Down
2 changes: 0 additions & 2 deletions ckan/logic/action/delete.py
Expand Up @@ -268,8 +268,6 @@ def task_status_delete(context, data_dict):
'''
model = context['model']
id = _get_or_bust(data_dict, 'id')
model.Session.remove()
model.Session()._context = context

entity = model.TaskStatus.get(id)

Expand Down
7 changes: 0 additions & 7 deletions ckan/logic/action/update.py
Expand Up @@ -106,7 +106,6 @@ def make_latest_pending_package_active(context, data_dict):

if not context.get('defer_commit'):
session.commit()
session.remove()


def related_update(context, data_dict):
Expand All @@ -128,7 +127,6 @@ def related_update(context, data_dict):
id = _get_or_bust(data_dict, "id")

schema = context.get('schema') or ckan.logic.schema.default_related_schema()
model.Session.remove()

related = model.Related.get(id)
context["related"] = related
Expand Down Expand Up @@ -169,7 +167,6 @@ def resource_update(context, data_dict):
user = context['user']
id = _get_or_bust(data_dict, "id")
schema = context.get('schema') or ckan.logic.schema.default_update_resource_schema()
model.Session.remove()

resource = model.Resource.get(id)
context["resource"] = resource
Expand Down Expand Up @@ -223,8 +220,6 @@ def package_update(context, data_dict):
model = context['model']
user = context['user']
name_or_id = data_dict.get("id") or data_dict['name']
model.Session.remove()
model.Session()._context = context

pkg = model.Package.get(name_or_id)
if pkg is None:
Expand Down Expand Up @@ -295,8 +290,6 @@ def package_update_validate(context, data_dict):
user = context['user']

id = _get_or_bust(data_dict, "id")
model.Session.remove()
model.Session()._context = context

pkg = model.Package.get(id)
context["package"] = pkg
Expand Down
9 changes: 5 additions & 4 deletions ckan/tests/functional/api/model/test_vocabulary.py
Expand Up @@ -42,6 +42,7 @@ def setup(self):
ckan.model.Session.commit()
self.sysadmin_user = ckan.model.User.get('admin')
self.normal_user = ckan.model.User.get('normal')
self.sysadmin_apikey = self.sysadmin_user.apikey

def clean_vocab(self):
ckan.model.Session.execute('delete from package_tag_revision')
Expand Down Expand Up @@ -237,7 +238,7 @@ def test_vocabulary_create_with_tags(self):
response = self._post('/api/action/vocabulary_create',
params=params,
extra_environ = {'Authorization':
str(self.sysadmin_user.apikey)})
str(self.sysadmin_apikey)})
assert response['success'] == True
assert response['result']
created_vocab = response['result']
Expand Down Expand Up @@ -284,7 +285,7 @@ def test_vocabulary_create_bad_tags(self):
response = self.app.post('/api/action/vocabulary_create',
params=json.dumps(params),
extra_environ = {'Authorization':
str(self.sysadmin_user.apikey)},
str(self.sysadmin_apikey)},
status=409)
assert response.json['success'] == False
assert response.json['error'].has_key('tags')
Expand Down Expand Up @@ -367,7 +368,7 @@ def test_vocabulary_create_invalid_name(self):
response = self.app.post('/api/action/vocabulary_create',
params=param_string,
extra_environ = {'Authorization':
str(self.sysadmin_user.apikey)},
str(self.sysadmin_apikey)},
status=409)
assert response.json['success'] == False
assert response.json['error']['name']
Expand Down Expand Up @@ -750,7 +751,7 @@ def test_add_tag_invalid_name(self):
response = self.app.post('/api/action/tag_create',
params=tag_string,
extra_environ = {'Authorization':
str(self.sysadmin_user.apikey)},
str(self.sysadmin_apikey)},
status=409)
assert response.json['success'] == False
assert response.json['error']['name']
Expand Down
151 changes: 27 additions & 124 deletions doc/organizations_and_groups.rst
Expand Up @@ -80,7 +80,7 @@ User Stories that apply to both Organizations and Groups

* **Anyone** can see a list of all the site's organizations.
* **Anyone** can see a list of all the site's groups.
* **Anyone** can see a list of all an organization's _public_ datasets
* **Anyone** can see a list of all an organization's _public_ datasets
* **Anyone** can see a list of all a group's datasets (groups can't have
private datasets, they're all public)
* **Sysadmins** can create new organizations, and automatically become admins
Expand Down Expand Up @@ -141,7 +141,7 @@ organization is specified. Users who are not a member of an organization will
be able to add datasets to this default organization.

* **Sysadmins** can move datasets from one organization to another.

* **Sysadmins** can delete organizations, and this deletes all of the
organization's datasets.

Expand Down Expand Up @@ -188,150 +188,53 @@ Technical FAQ


The data model will not change from how it is currently::

+------------+
| |
+---+ dataset |
+------------+ +-----------+ | | |
| | | +---+ +------------+
| group +-----+ member |
| group +-----+ member |
| | | +---+ +------------+
+------------+ +-----------+ | | |
+---+ user |
| |
+------------+

The group table has a "type" field specifying if the table is an "organization"
or a "group".
The group table has a "type" field specifying if the table is an "organization"
or a "group".

Using the one 'group' table for both organizations and groups means you can't
have an organization and a group with the same name. This is probably a good
thing as it would be confusing for users anyway.

The member table has field called capacity which should be used as follows:

* When a dataset is a member of an Organization it must have capacity of
either public/private.
* When a dataset is a member of a Group it must have capacity of 'member'.
* When a user is a member of a Group/Organization it must have capacity
of admin/editor.


Transition
==========


I'd remove the member table as horrible and move to this model
::


+------------+
| |
+---+ dataset |
+-----------+ | | |
| group +---+ +------------+
| ownership |
| +---+ +------------+
+-----------+ | | |
+---+ group |
| |
+------------+



+------------+
| |
+---+ user |
+-----------+ | | |
| group +---+ +------------+
| membership|
| +---+ +------------+
+-----------+ | | |
+---+ group |
| |
+------------+

+----------------+
|group_membership|
+----------------+
|Group/Org |
|User |
|Role |
+----------------+

+----------------+
|group_ownership |
+----------------+
|Group/Org |
|Dataset |
+----------------+

Orgs would just be a group type with it's own forms and a field that
destiguishes it as an org. Probably it's own schema etc

An organisation would only be different from a group by this type unless I
am given explict differences (note: I have no real knowledge of groups only
that in the code)

If possible all actions will just be group_.... not organization_....

Any changes to the group model would be as minimal as possible


Admin
`````

Need to add some stuff to allow admin of group datasets etc both for
admin/sysadmins


Searches
````````

Search Indexes would be updated to contain privacy information for groups

Searches would be updated to not return private data. This may need some
thought to keep things running fast - public users would almost definatly be
a special case as this is a common usage


Need methods for group/org applications and admin

Do we need to move/migrate existing data?

Group/Org searches should seem different to the user so searching groups
only shows groups etc

I may need some help with the search stuff

Auth
````

All auth functions would be group_... but these would then internally use
the org_... functionality if the group is an org

Try to remove any old auth stuff if possible
The member table has field called capacity which should be used as follows:

Permissions to just be hard coded (as user stories) in this first phase but
keep an eye on future upgrades
* When a dataset is a member of an Organization it must have capacity of
'ozganization'.
* When a dataset is a member of a Group it must have capacity of 'member'.
* When a user is a member of a Group/Organization it must have capacity
of the users role eg. admin, editor, memeber

Sysadmins will have magic powers to see do anything

The package table has gained two new fields

Tests
`````
owner_org - the id of the owning organization
private - determines if the dataset is public or private
`
Config options
==============

Attempt to keep existing tests running and look at some tests for new
functionality.
The following config options have been created.

Misc
````
ckan.auth.user_create_organizations
ckan.auth.user_create_groups

There will be some integration issues but they are outside the scope of this
doc and the development cycle
ckan.auth.create_user_via_api
ckan.auth.create_dataset_if_not_in_organization

API
```
ckan.auth.anon_create_dataset
ckan.auth.user_delete_groups

Only actions will be supported for orgs - any v1/2 apis will only work for
groups orgs will 500
ckan.auth.user_delete_organizations
ckan.auth.create_unowned_dataset

0 comments on commit bbff265

Please sign in to comment.