Skip to content

Commit

Permalink
conflict with master
Browse files Browse the repository at this point in the history
  • Loading branch information
smotornyuk committed Feb 21, 2017
2 parents 5b675eb + e9d58bb commit cc1d304
Show file tree
Hide file tree
Showing 9 changed files with 87 additions and 15 deletions.
2 changes: 2 additions & 0 deletions ckan/logic/action/create.py
Expand Up @@ -60,6 +60,8 @@ def package_create(context, data_dict):
:param title: the title of the dataset (optional, default: same as
``name``)
:type title: string
:param private: If ``True`` creates a private dataset
:type private: bool
:param author: the name of the dataset's author (optional)
:type author: string
:param author_email: the email address of the dataset's author (optional)
Expand Down
3 changes: 1 addition & 2 deletions ckan/model/resource.py
Expand Up @@ -48,7 +48,7 @@
Column('mimetype', types.UnicodeText),
Column('mimetype_inner', types.UnicodeText),
Column('size', types.BigInteger),
Column('created', types.DateTime, default=datetime.datetime.now),
Column('created', types.DateTime, default=datetime.datetime.utcnow),
Column('last_modified', types.DateTime),
Column('cache_url', types.UnicodeText),
Column('cache_last_updated', types.DateTime),
Expand Down Expand Up @@ -189,7 +189,6 @@ def activity_stream_detail(self, activity_id, activity_type):
),
)
},
order_by=[resource_table.c.package_id],
extension=[vdm.sqlalchemy.Revisioner(resource_revision_table),
extension.PluginMapperExtension(),
],
Expand Down
42 changes: 33 additions & 9 deletions ckan/model/user.py
Expand Up @@ -9,7 +9,7 @@
from passlib.hash import pbkdf2_sha512
from sqlalchemy.sql.expression import or_
from sqlalchemy.orm import synonym
from sqlalchemy import types, Column, Table
from sqlalchemy import types, Column, Table, func
import vdm.sqlalchemy

import meta
Expand Down Expand Up @@ -194,21 +194,45 @@ def as_dict(self):
def number_of_edits(self):
# have to import here to avoid circular imports
import ckan.model as model
revisions_q = meta.Session.query(model.Revision)
revisions_q = revisions_q.filter_by(author=self.name)
return revisions_q.count()

# Get count efficiently without spawning the SQLAlchemy subquery
# wrapper. Reset the VDM-forced order_by on timestamp.
return meta.Session.execute(
meta.Session.query(
model.Revision
).filter_by(
author=self.name
).statement.with_only_columns(
[func.count()]
).order_by(
None
)
).scalar()

def number_created_packages(self, include_private_and_draft=False):
# have to import here to avoid circular imports
import ckan.model as model
q = meta.Session.query(model.Package)\
.filter_by(creator_user_id=self.id)

# Get count efficiently without spawning the SQLAlchemy subquery
# wrapper. Reset the VDM-forced order_by on timestamp.
q = meta.Session.query(
model.Package
).filter_by(
creator_user_id=self.id
)

if include_private_and_draft:
q = q.filter(model.Package.state != 'deleted')
else:
q = q.filter_by(state='active')\
.filter_by(private=False)
return q.count()
q = q.filter_by(state='active', private=False)

return meta.Session.execute(
q.statement.with_only_columns(
[func.count()]
).order_by(
None
)
).scalar()

def activate(self):
''' Activate the user '''
Expand Down
2 changes: 1 addition & 1 deletion ckan/templates/package/resource_read.html
Expand Up @@ -55,7 +55,7 @@
{% if res.url and h.is_url(res.url) %}
<p class="muted ellipsis">{{ _('URL:') }} <a class="resource-url-analytics" href="{{ res.url }}" title="{{ res.url }}">{{ res.url }}</a></p>
{% elif res.url %}
<p class="muted ellipsis">{{ _('URL:') }} {{ res.url }}</p>
<p class="muted break-word">{{ _('URL:') }} {{ res.url }}</p>
{% endif %}
{% endblock %}
<div class="prose notes" property="rdfs:label">
Expand Down
3 changes: 2 additions & 1 deletion ckan/templates/package/resources.html
Expand Up @@ -11,8 +11,9 @@
{% block primary_content_inner %}
{% if pkg.resources %}
<ul class="resource-list"{% if has_reorder %} data-module="resource-reorder" data-module-id="{{ pkg.id }}"{% endif %}>
{% set can_edit = h.check_access('package_update', {'id':pkg.id }) %}
{% for resource in pkg.resources %}
{% snippet 'package/snippets/resource_item.html', pkg=pkg, res=resource, url_is_edit=true %}
{% snippet 'package/snippets/resource_item.html', pkg=pkg, res=resource, url_is_edit=true, can_edit=can_edit %}
{% endfor %}
</ul>
{% else %}
Expand Down
1 change: 0 additions & 1 deletion ckan/templates/package/snippets/resource_item.html
@@ -1,4 +1,3 @@
{% set can_edit = h.check_access('package_update', {'id':pkg.id }) %}
{% set url_action = 'resource_edit' if url_is_edit and can_edit else 'resource_read' %}
{% set url = h.url_for(controller='package', action=url_action, id=pkg.name, resource_id=res.id) %}

Expand Down
3 changes: 2 additions & 1 deletion ckan/templates/package/snippets/resources_list.html
Expand Up @@ -15,8 +15,9 @@ <h3>{{ _('Data and Resources') }}</h3>
{% if resources %}
<ul class="{% block resource_list_class %}resource-list{% endblock %}">
{% block resource_list_inner %}
{% set can_edit = h.check_access('package_update', {'id':pkg.id }) %}
{% for resource in resources %}
{% snippet 'package/snippets/resource_item.html', pkg=pkg, res=resource %}
{% snippet 'package/snippets/resource_item.html', pkg=pkg, res=resource, can_edit=can_edit %}
{% endfor %}
{% endblock %}
</ul>
Expand Down
24 changes: 24 additions & 0 deletions ckanext/datastore/plugin.py
Expand Up @@ -6,6 +6,9 @@
import ckan.plugins as p
import ckan.logic as logic
import ckan.model as model
from ckan.model.core import State

import ckanext.datastore.db as db
import ckanext.datastore.logic.action as action
import ckanext.datastore.logic.auth as auth
import ckanext.datastore.interfaces as interfaces
Expand Down Expand Up @@ -155,6 +158,27 @@ def before_show(self, resource_dict):

return resource_dict

def after_delete(self, context, resources):
model = context['model']
pkg = context['package']
res_query = model.Session.query(model.Resource)
query = res_query.filter(
model.Resource.package_id == pkg.id,
model.Resource.state == State.DELETED
)
deleted = [
res for res in query.all()
if res.extras.get('datastore_active') is True]

for res in deleted:
db.delete(context, {
'resource_id': res.id,
'connection_url': self.write_url
})
res.extras['datastore_active'] = False
res_query.update(
{'extras': res.extras}, synchronize_session=False)

# IDatastore

def datastore_validate(self, *pargs, **kwargs):
Expand Down
22 changes: 22 additions & 0 deletions ckanext/datastore/tests/test_delete.py
Expand Up @@ -11,10 +11,15 @@
import ckan.model as model
import ckan.tests.legacy as tests
from ckan.common import config
import ckan.tests.factories as factories
import ckan.tests.helpers as helpers
from ckan.logic import NotFound

import ckanext.datastore.db as db
from ckanext.datastore.tests.helpers import rebuild_all_dbs, set_url_type

assert_raises = nose.tools.assert_raises


class TestDatastoreDelete(tests.WsgiAppCase):
sysadmin_user = None
Expand Down Expand Up @@ -99,6 +104,23 @@ def test_delete_basic(self):

self.Session.remove()

def test_datastore_deleted_during_resource_deletion(self):
package = factories.Dataset()
data = {
'resource': {
'boo%k': 'crime',
'author': ['tolstoy', 'dostoevsky'],
'package_id': package['id']
},
}
result = helpers.call_action('datastore_create', **data)
resource_id = result['resource_id']
helpers.call_action('resource_delete', id=resource_id)

assert_raises(
NotFound, helpers.call_action, 'datastore_search',
resource_id=resource_id)

def test_delete_invalid_resource_id(self):
postparams = '%s=1' % json.dumps({'resource_id': 'bad'})
auth = {'Authorization': str(self.sysadmin_user.apikey)}
Expand Down

0 comments on commit cc1d304

Please sign in to comment.