Skip to content

Commit 480100f

Browse files
authored
Merge pull request #3316 from kobotoolbox/sync-media-on-redeploy
Synchronize media files when redeploying a project with no changes
2 parents b6e4435 + 148f190 commit 480100f

File tree

8 files changed

+60
-8
lines changed

8 files changed

+60
-8
lines changed

jsapp/js/components/modalForms/formMedia.es6

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,13 @@ class FormMedia extends React.Component {
212212
return (
213213
<bem.FormView m='form-media'>
214214
<bem.FormMedia>
215+
{this.props.asset.deployment__active &&
216+
<bem.FormView__cell m='warning'>
217+
<i className='k-icon k-icon-alert' />
218+
<p>{t('You must redeploy this form to see media changes.')}</p>
219+
</bem.FormView__cell>
220+
}
221+
215222
<bem.FormMedia__title>
216223
<bem.FormMedia__label>
217224
{t('Attach files')}

jsapp/scss/components/_kobo.form-media.scss

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@
55
.form-media {
66
padding: 30px 40px;
77

8+
.form-view__cell--warning {
9+
margin-bottom: 24px;
10+
}
11+
812
.form-media__title {
913
display: inline-block;
1014
position: relative;

kpi/deployment_backends/kobocat_backend.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -843,6 +843,9 @@ def _upload_to_kc(file_):
843843
expect_formid=False,
844844
**kwargs)
845845

846+
file_.synced_with_backend = True
847+
file_.save(update_fields=['synced_with_backend'])
848+
846849
# Process deleted files in case two entries contain the same file but
847850
# one is flagged as deleted
848851
asset_files = self.asset.asset_files.filter(

kpi/deployment_backends/mixin.py

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,27 @@
11
# coding: utf-8
22
from kpi.constants import ASSET_TYPE_SURVEY
33
from kpi.exceptions import BadAssetTypeException
4+
from kpi.models.asset_file import AssetFile
45
from kpi.tasks import sync_media_files
56
from .backends import DEPLOYMENT_BACKENDS
67
from .base_backend import BaseDeploymentBackend
78

89

910
class DeployableMixin:
1011

12+
def async_media_files(self, force=True):
13+
"""
14+
Synchronize form media files with deployment backend asynchronously
15+
"""
16+
if force or self.asset_files.filter(
17+
file_type=AssetFile.FORM_MEDIA, synced_with_backend=False
18+
).exists():
19+
self.deployment.store_data(
20+
{'status': self.deployment.STATUS_NOT_SYNCED}
21+
)
22+
self.save(create_version=False, adjust_content=False)
23+
sync_media_files.delay(self.uid)
24+
1125
@property
1226
def can_be_deployed(self):
1327
return self.asset_type and self.asset_type == ASSET_TYPE_SURVEY
@@ -29,11 +43,7 @@ def deploy(self, backend=False, active=True):
2943
self.deployment.redeploy(active=active)
3044

3145
self._mark_latest_version_as_deployed()
32-
self.deployment.store_data(
33-
{'status': self.deployment.STATUS_NOT_SYNCED}
34-
)
35-
self.save(create_version=False, adjust_content=False)
36-
sync_media_files.delay(self.uid)
46+
self.async_media_files()
3747

3848
else:
3949
raise BadAssetTypeException(
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# Generated by Django 2.2.7 on 2021-06-25 17:54
2+
3+
from django.db import migrations, models
4+
import kpi.models.import_export_task
5+
import private_storage.fields
6+
import private_storage.storage.s3boto3
7+
8+
9+
class Migration(migrations.Migration):
10+
11+
dependencies = [
12+
('kpi', '0036_add_date_deleted_field_to_asset_file'),
13+
]
14+
15+
operations = [
16+
migrations.AddField(
17+
model_name='assetfile',
18+
name='synced_with_backend',
19+
field=models.BooleanField(default=False),
20+
),
21+
]

kpi/models/asset_file.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ class AssetFile(OpenRosaManifestInterface, models.Model):
6767
content = PrivateFileField(upload_to=upload_to, max_length=380, null=True)
6868
metadata = JSONBField(default=dict)
6969
date_deleted = models.DateTimeField(null=True, default=None)
70+
synced_with_backend = models.BooleanField(default=False)
7071

7172
def delete(self, using=None, keep_parents=False, force=False):
7273
# Delete object and files on storage if `force` is True or file type
@@ -78,7 +79,8 @@ def delete(self, using=None, keep_parents=False, force=False):
7879

7980
# Otherwise, just flag the file as deleted.
8081
self.date_deleted = timezone.now()
81-
self.save(update_fields=['date_deleted'])
82+
self.synced_with_backend = False
83+
self.save(update_fields=['date_deleted', 'synced_with_backend'])
8284

8385
@property
8486
def filename(self):

kpi/serializers/v1/deployment.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,11 @@ def update(self, instance, validated_data):
6363
active=validated_data.get('active', deployment.active)
6464
)
6565
elif 'active' in validated_data:
66+
active = validated_data['active']
6667
# Set the `active` flag without touching the rest of the deployment
67-
deployment.set_active(validated_data['active'])
68+
deployment.set_active(active)
69+
# If we (re)activate the asset, let's synchronize its media files
70+
if active:
71+
asset.async_media_files(force=False)
6872

6973
return deployment

kpi/tests/api/v2/test_api_assets.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -975,7 +975,8 @@ def test_upload_form_media_bad_mime_type(self):
975975
json_response = response.json()
976976
expected_response = {
977977
'metadata': ['Only `image`, `audio`, `video`, `text/csv`, '
978-
'`application/xml` MIME types are allowed']
978+
'`application/xml`, `application/zip` '
979+
'MIME types are allowed']
979980
}
980981
assert json_response == expected_response
981982

0 commit comments

Comments
 (0)