Repository: ckan/ckan

Issue:
Full URL of the resource stored in the DB
### CKAN Version if known (or site URL)
2.6+
Reported in #4070 

### Please describe the expected behaviour
When editing resource metadata, we should store the filename in the database, at `resource` table `URL` column. 

### Please describe the actual behaviour
When editing resource metadata, full URL is saved in the database

### What steps can be taken to reproduce the issue? 
1.Go to edit resource page
2.Save the changes

I've tested of this occurs on edit dataset and the issue is not reproducible.It occurs only on edit resource.

This occurs because we are generating the full url on [reading](https://github.com/ckan/ckan/blob/master/ckan/lib/dictization/model_dictize.py#L110) the resource and it is stored as it in the DB on save


Discussion:
Here what's happening:

* When creating the resource, the uploader stores just the file name in the `url` field
* This is what gets stored in the database, by `ckan.lib.dictization.model_save.resource_dict_save()`

So far so good.

Now, when we add a new resource to the same dataset, or edit the existing resource:

* `resource_create` and `resource_update` call `package_show` internally to update the whole dataset dict with the new/updated resource and pass it to `package_update`.
* `package_show` (correctly) translates the single file name in `url` to a fully qualified URL so it can be displayed in the frontend or the API
* But we are passing the dict with fully qualified URLs to `package_update`, which will store them on the database

We need to strip the full URL and store just the file name again when storing resources (only for resources where `url_type=upload` of course!). We can do that:

1. At the [`model_save.resource_dict_save`](https://github.com/ckan/ckan/blob/master/ckan/lib/dictization/model_save.py#L16) level
2. At the  [`default_update_resource_schema`](https://github.com/ckan/ckan/blob/master/ckan/logic/schema.py#L61) level (validation)

Note that the creation of the fully qualified URL is done at the same level of 1 in [`model_dictize.resource_dictize`](https://github.com/ckan/ckan/blob/master/ckan/lib/dictization/model_dictize.py#L100) so perhaps it make sense to be consistent and do it there as well.

Resolving patch:
diff --git a/ckan/lib/dictization/model_dictize.py b/ckan/lib/dictization/model_dictize.py
--- a/ckan/lib/dictization/model_dictize.py
+++ b/ckan/lib/dictization/model_dictize.py
@@ -108,6 +108,7 @@ def resource_dictize(res, context):
     ## for_edit is only called at the times when the dataset is to be edited
     ## in the frontend. Without for_edit the whole qualified url is returned.
     if resource.get('url_type') == 'upload' and not context.get('for_edit'):
+        url = url.rsplit('/')[-1]
         cleaned_name = munge.munge_filename(url)
         resource['url'] = h.url_for('resource.download',
                                     id=resource['package_id'],
diff --git a/ckan/lib/dictization/model_save.py b/ckan/lib/dictization/model_save.py
--- a/ckan/lib/dictization/model_save.py
+++ b/ckan/lib/dictization/model_save.py
@@ -13,7 +13,9 @@
 
 log = logging.getLogger(__name__)
 
+
 def resource_dict_save(res_dict, context):
+
     model = context["model"]
     session = context["session"]
 
@@ -30,6 +32,10 @@ def resource_dict_save(res_dict, context):
     table = class_mapper(model.Resource).mapped_table
     fields = [field.name for field in table.c]
 
+    # Strip the full url for resources of type 'upload'
+    if res_dict.get('url') and res_dict.get('url_type') == u'upload':
+        res_dict['url'] = res_dict['url'].rsplit('/')[-1]
+
     # Resource extras not submitted will be removed from the existing extras
     # dict
     new_extras = {}


Test patch:
diff --git a/ckan/tests/lib/dictization/test_model_dictize.py b/ckan/tests/lib/dictization/test_model_dictize.py
--- a/ckan/tests/lib/dictization/test_model_dictize.py
+++ b/ckan/tests/lib/dictization/test_model_dictize.py
@@ -5,7 +5,7 @@
 
 from nose.tools import assert_equal
 
-from ckan.lib.dictization import model_dictize
+from ckan.lib.dictization import model_dictize, model_save
 from ckan import model
 from ckan.lib import search
 
@@ -401,8 +401,7 @@ def test_package_dictize_resource(self):
 
         result = model_dictize.package_dictize(dataset_obj, context)
 
-        assert_equal_for_keys(result['resources'][0], resource,
-                              'name', 'url')
+        assert_equal_for_keys(result['resources'][0], resource, 'name', 'url')
         expected_dict = {
             u'cache_last_updated': None,
             u'cache_url': None,
@@ -422,6 +421,40 @@ def test_package_dictize_resource(self):
         }
         self.assert_equals_expected(expected_dict, result['resources'][0])
 
+    def test_package_dictize_resource_upload_and_striped(self):
+        dataset = factories.Dataset()
+        resource = factories.Resource(package=dataset['id'],
+                                      name='test_pkg_dictize',
+                                      url_type='upload',
+                                      url='some_filename.csv')
+
+        context = {'model': model, 'session': model.Session}
+
+        result = model_save.resource_dict_save(resource, context)
+
+        expected_dict = {
+            u'url': u'some_filename.csv',
+            u'url_type': u'upload'
+        }
+        assert expected_dict['url'] == result.url
+
+    def test_package_dictize_resource_upload_with_url_and_striped(self):
+        dataset = factories.Dataset()
+        resource = factories.Resource(package=dataset['id'],
+                                      name='test_pkg_dictize',
+                                      url_type='upload',
+                                      url='http://some_filename.csv')
+
+        context = {'model': model, 'session': model.Session}
+
+        result = model_save.resource_dict_save(resource, context)
+
+        expected_dict = {
+            u'url': u'some_filename.csv',
+            u'url_type': u'upload'
+        }
+        assert expected_dict['url'] == result.url
+
     def test_package_dictize_tags(self):
         dataset = factories.Dataset(tags=[{'name': 'fish'}])
         dataset_obj = model.Package.get(dataset['id'])