2019-08-05 14:25:20 +00:00
|
|
|
from django_kepi.models import *
|
2019-08-12 18:31:38 +00:00
|
|
|
import django.db.utils
|
2019-06-27 16:19:02 +00:00
|
|
|
import logging
|
|
|
|
|
|
|
|
logger = logging.getLogger(name='django_kepi')
|
|
|
|
|
|
|
|
def create(
|
2019-07-18 13:23:33 +00:00
|
|
|
is_local_user=True,
|
2019-06-27 16:19:02 +00:00
|
|
|
run_side_effects=True,
|
2019-07-31 18:49:42 +00:00
|
|
|
run_delivery=True,
|
|
|
|
value=None,
|
|
|
|
**kwargs):
|
|
|
|
|
|
|
|
from django_kepi.delivery import deliver
|
2019-06-27 16:19:02 +00:00
|
|
|
|
2019-08-05 12:09:43 +00:00
|
|
|
if value is None:
|
2019-08-12 18:31:38 +00:00
|
|
|
value = {}
|
|
|
|
|
|
|
|
# Remove the "f_" prefix, which exists so that we can write
|
|
|
|
# things like f_type or f_object without using reserved keywords.
|
|
|
|
for k,v in kwargs.items():
|
|
|
|
if k.startswith('f_'):
|
|
|
|
value[k[2:]] = v
|
|
|
|
else:
|
|
|
|
value[k] = v
|
2019-08-05 12:09:43 +00:00
|
|
|
|
2019-07-08 23:44:52 +00:00
|
|
|
logger.info("Create begins: source is %s; local? %s; run side effects? %s",
|
2019-07-18 13:23:33 +00:00
|
|
|
value, is_local_user, run_side_effects)
|
2019-07-08 23:44:52 +00:00
|
|
|
|
2019-07-31 18:49:42 +00:00
|
|
|
if value is None:
|
2019-08-05 14:25:20 +00:00
|
|
|
logger.warn(" -- it's ludicrous to create an Object with no value")
|
2019-08-05 12:09:43 +00:00
|
|
|
return None
|
2019-07-31 18:49:42 +00:00
|
|
|
|
2019-06-27 16:19:02 +00:00
|
|
|
# Now, let's fix the types of keys and values.
|
|
|
|
|
|
|
|
if 'type' not in value:
|
2019-08-05 14:25:20 +00:00
|
|
|
logger.warn("Objects must have a type; dropping message")
|
2019-08-05 12:09:43 +00:00
|
|
|
return None
|
2019-06-27 16:19:02 +00:00
|
|
|
|
|
|
|
value['type'] = value['type'].title()
|
|
|
|
|
2019-08-12 18:31:38 +00:00
|
|
|
for k,v in value.copy().items():
|
|
|
|
if not isinstance(k, str):
|
|
|
|
logger.warn('Objects can only have keys which are strings: %s',
|
|
|
|
str(k))
|
|
|
|
del value[k]
|
|
|
|
|
2019-06-27 16:19:02 +00:00
|
|
|
if 'id' in value:
|
2019-07-18 13:23:33 +00:00
|
|
|
if is_local_user:
|
2019-08-05 14:25:20 +00:00
|
|
|
logger.warn('Removing "id" field at local Object creation')
|
2019-06-27 16:19:02 +00:00
|
|
|
del value['id']
|
|
|
|
else:
|
2019-07-18 13:23:33 +00:00
|
|
|
if not is_local_user:
|
2019-08-05 14:25:20 +00:00
|
|
|
logger.warn("Remote Objects must have an id; dropping message")
|
2019-08-05 12:09:43 +00:00
|
|
|
return None
|
2019-06-27 16:19:02 +00:00
|
|
|
|
2019-06-29 15:40:47 +00:00
|
|
|
try:
|
2019-07-05 16:23:50 +00:00
|
|
|
import django_kepi.models as kepi_models
|
2019-08-05 14:25:20 +00:00
|
|
|
cls = getattr(locals()['kepi_models'], value['type'])
|
2019-08-10 17:58:49 +00:00
|
|
|
except AttributeError:
|
|
|
|
logger.warn("There's no type called %s",
|
|
|
|
value['type'])
|
|
|
|
return None
|
2019-06-29 15:40:47 +00:00
|
|
|
except KeyError:
|
2019-08-10 17:58:49 +00:00
|
|
|
logger.warn("The class '%s' wasn't exported properly. "+\
|
|
|
|
"This shouldn't happen.",
|
|
|
|
value['type'])
|
2019-06-29 15:40:47 +00:00
|
|
|
return None
|
|
|
|
|
|
|
|
logger.debug('Class for %s is %s', value['type'], cls)
|
2019-08-05 14:25:20 +00:00
|
|
|
del value['type']
|
2019-06-27 16:19:02 +00:00
|
|
|
|
2019-08-12 22:53:08 +00:00
|
|
|
if 'url' in value and 'remote_url' in value:
|
2019-08-12 18:31:38 +00:00
|
|
|
if value['url']!=value['remote_url']:
|
|
|
|
logger.warn('url and remote_url differ (%s vs %s)',
|
|
|
|
value['url'], value['remote_url'])
|
|
|
|
|
|
|
|
# in either case there's no point in keeping url around
|
|
|
|
del value['url']
|
|
|
|
|
2019-08-13 19:22:00 +00:00
|
|
|
if 'id' in value and 'url' in value:
|
|
|
|
if value['id']!=value['url']:
|
|
|
|
logger.warn('id and url differ (%s vs %s)',
|
|
|
|
value['id'], value['url'])
|
|
|
|
del value['url']
|
|
|
|
|
2019-07-03 11:20:04 +00:00
|
|
|
########################
|
|
|
|
|
2019-07-02 23:48:58 +00:00
|
|
|
# Right, we need to create an object.
|
2019-06-27 16:19:02 +00:00
|
|
|
|
2019-07-02 23:48:58 +00:00
|
|
|
if 'id' in value:
|
2019-08-12 18:31:38 +00:00
|
|
|
try:
|
|
|
|
result = cls(
|
|
|
|
remote_url = value['id'],
|
|
|
|
)
|
|
|
|
del value['id']
|
|
|
|
result.save()
|
2019-08-13 19:22:00 +00:00
|
|
|
logger.warn(' -- created local copy of remote object %s '+\
|
|
|
|
'(url was %s)',
|
|
|
|
result, result.remote_url)
|
2019-08-12 18:31:38 +00:00
|
|
|
except django.db.utils.IntegrityError:
|
|
|
|
logger.warn('We already have an object with remote_url=%s',
|
|
|
|
value['id'])
|
|
|
|
return None
|
|
|
|
else:
|
|
|
|
result = cls(
|
|
|
|
)
|
|
|
|
result.save()
|
2019-08-13 19:22:00 +00:00
|
|
|
logger.warn(' -- created local object %s',
|
|
|
|
result)
|
2019-07-02 23:48:58 +00:00
|
|
|
|
2019-07-03 11:20:04 +00:00
|
|
|
for f,v in value.items():
|
2019-08-12 18:31:38 +00:00
|
|
|
try:
|
|
|
|
result[f] = v
|
|
|
|
except django.db.utils.Error as pe:
|
|
|
|
logger.warn('Can\'t set %s=%s on the new object (%s); bailing',
|
|
|
|
f, v, pe)
|
|
|
|
return None
|
2019-07-02 23:48:58 +00:00
|
|
|
|
2019-08-05 12:09:43 +00:00
|
|
|
if hasattr(result, '_after_create'):
|
|
|
|
result._after_create()
|
|
|
|
|
2019-06-27 16:19:02 +00:00
|
|
|
if run_side_effects:
|
2019-08-10 16:28:31 +00:00
|
|
|
success = result.run_side_effects()
|
|
|
|
if not success:
|
|
|
|
logger.debug(' -- deleting original object')
|
|
|
|
try:
|
|
|
|
# FIXME This fails because "delete" is a type name!
|
|
|
|
result.delete()
|
|
|
|
except:
|
|
|
|
logger.debug(' -- deletion failed; marking inactive')
|
|
|
|
result.active = False
|
|
|
|
result.save()
|
|
|
|
return None
|
2019-06-27 16:19:02 +00:00
|
|
|
|
2019-07-31 18:49:42 +00:00
|
|
|
if run_delivery:
|
|
|
|
deliver(result.number,
|
|
|
|
incoming = True)
|
|
|
|
|
2019-06-27 16:19:02 +00:00
|
|
|
return result
|
|
|
|
|