Skip to content

Commit

Permalink
Added 'is_import' and 'no_touch' options, this makes it possible to i…
Browse files Browse the repository at this point in the history
…mport data from other sites and keep the original created/modified dates.
  • Loading branch information
mworrell committed Mar 22, 2012
1 parent fb4a6df commit 15d13db
Show file tree
Hide file tree
Showing 3 changed files with 90 additions and 28 deletions.
25 changes: 16 additions & 9 deletions src/models/m_edge.erl
Expand Up @@ -32,6 +32,7 @@
get_id/4,
get_edges/2,
insert/4,
insert/5,
delete/2,
delete/4,
delete_multiple/4,
Expand Down Expand Up @@ -122,22 +123,28 @@ get_edges(SubjectId, Context) ->
end.

%% Insert a new edge
insert(SubjectId, PredId, ObjectId, Context) when is_integer(PredId) ->
insert(SubjectId, Pred, ObjectId, Context) ->
insert(SubjectId, Pred, ObjectId, [], Context).

insert(SubjectId, PredId, ObjectId, Opts, Context) when is_integer(PredId) ->
case m_predicate:is_predicate(PredId, Context) of
true -> insert1(SubjectId, PredId, ObjectId, Context);
true -> insert1(SubjectId, PredId, ObjectId, Opts, Context);
false -> throw({error, {unknown_predicate, PredId}})
end;
insert(SubjectId, Pred, ObjectId, Context) ->
insert(SubjectId, Pred, ObjectId, Opts, Context) ->
PredId = m_predicate:name_to_id_check(Pred, Context),
insert1(SubjectId, PredId, ObjectId, Context).
insert1(SubjectId, PredId, ObjectId, Context) ->
insert1(SubjectId, PredId, ObjectId, Opts, Context).

insert1(SubjectId, PredId, ObjectId, Opts, Context) ->
case z_db:q1("select id from edge where subject_id = $1 and object_id = $2 and predicate_id = $3", [SubjectId, ObjectId, PredId], Context) of
undefined ->
F = fun(Ctx) ->
m_rsc:touch(SubjectId, Ctx),
z_db:insert(edge, [{subject_id, SubjectId}, {object_id, ObjectId}, {predicate_id, PredId}], Ctx)
end,
case proplists:is_defined(no_touch, Opts) of
true -> skip;
false -> m_rsc:touch(SubjectId, Ctx)
end,
z_db:insert(edge, [{subject_id, SubjectId}, {object_id, ObjectId}, {predicate_id, PredId}], Ctx)
end,

{ok, PredName} = m_predicate:id_to_name(PredId, Context),
case z_acl:is_allowed(insert, #acl_edge{subject_id=SubjectId, predicate=PredName, object_id=ObjectId}, Context) of
Expand Down
63 changes: 48 additions & 15 deletions src/models/m_media.erl
Expand Up @@ -31,6 +31,7 @@
m_value/2,
identify/2,
get/2,
get_file_data/2,
get_by_filename/2,
exists/2,
depiction/2,
Expand All @@ -42,6 +43,7 @@
replace_file/3,
replace_file/4,
replace_file/5,
replace_file/6,
insert_url/2,
insert_url/3,
replace_url/4,
Expand Down Expand Up @@ -117,6 +119,26 @@ get(Id, Context) ->
F = fun() -> z_db:assoc_props_row("select * from medium where id = $1", [Id], Context) end,
z_depcache:memo(F, {medium, Id}, ?WEEK, [Id], Context).

%% @doc Return the contents of the file belonging to the media resource
get_file_data(Id, Context) ->
case get(Id, Context) of
undefined ->
{error, enoent};
Media ->
Filename = proplists:get_value(filename, Media),
ArchivedFilename = z_media_archive:abspath(Filename, Context),
case file:read_file(ArchivedFilename) of
{ok, Data} ->
#upload{
filename=Filename,
data=Data,
mime=proplists:get_value(mime, Media)
};
Error ->
Error
end
end.

%% @doc Fetch a medium by filename
get_by_filename(Filename, Context) ->
case z_depcache:get({medium, Filename}, Context) of
Expand Down Expand Up @@ -253,41 +275,44 @@ insert_file_mime_ok(File, Props1, PropsMedia, Context) ->
undefined -> [{title, proplists:get_value(original_filename, Props2)}|Props2];
_ -> Props2
end,
replace_file_mime_ok(File, insert_rsc, Props3, PropsMedia, Context).
replace_file_mime_ok(File, insert_rsc, Props3, PropsMedia, [], Context).


%% @doc Replaces a medium file, when the file is not in archive then a copy is made in the archive.
%% When the resource is in the media category, then the category is adapted depending on the mime type of the uploaded file.
%% @spec replace_file(File, RscId, Context) -> {ok, Id} | {error, Reason}
replace_file(File, RscId, Context) ->
replace_file(File, RscId, [], Context).
replace_file(File, RscId, [], [], Context).

replace_file(File, RscId, Props, Context) ->
replace_file(File, RscId, Props, [], Context).


replace_file(#upload{filename=OriginalFilename, data=Data, tmpfile=undefined}, RscId, Props, Context) when Data /= undefined ->
replace_file(#upload{filename=OriginalFilename, data=Data, tmpfile=undefined}, RscId, Props, Opts, Context) when Data /= undefined ->
TmpFile = z_tempfile:new(),
ok = file:write_file(TmpFile, Data),
replace_file(#upload{filename=OriginalFilename, data=Data, tmpfile=TmpFile}, RscId, Props, Context);
replace_file(#upload{filename=OriginalFilename, data=Data, tmpfile=TmpFile}, RscId, Props, Opts, Context);

replace_file(#upload{filename=OriginalFilename, tmpfile=TmpFile}, RscId, Props, Context) ->
replace_file(#upload{filename=OriginalFilename, tmpfile=TmpFile}, RscId, Props, Opts, Context) ->
PropsMedia = add_medium_info(TmpFile, OriginalFilename, [{original_filename, OriginalFilename}], Context),
replace_file(TmpFile, RscId, [{original_filename, OriginalFilename}|Props], PropsMedia, Context);
replace_file(TmpFile, RscId, [{original_filename, OriginalFilename}|Props], PropsMedia, Opts, Context);

replace_file(File, RscId, Props, Context) ->
replace_file(File, RscId, Props, Opts, Context) ->
OriginalFilename = proplists:get_value(original_filename, Props, File),
PropsMedia = add_medium_info(File, OriginalFilename, [{original_filename, OriginalFilename}], Context),
replace_file(File, RscId, Props, PropsMedia, Context).
replace_file(File, RscId, Props, PropsMedia, Opts, Context).

replace_file(File, RscId, Props, PropsMedia, Context) ->
replace_file(File, RscId, Props, PropsMedia, Opts, Context) ->
Mime = proplists:get_value(mime, PropsMedia),
case z_acl:is_allowed(insert, #acl_media{mime=Mime, size=filelib:file_size(File)}, Context) of
true ->
replace_file_mime_ok(File, RscId, Props, PropsMedia, Context);
replace_file_mime_ok(File, RscId, Props, PropsMedia, Opts, Context);
false ->
{error, file_not_allowed}
end.

%% @doc Replace the file, no mime check needed.
replace_file_mime_ok(File, RscId, Props, PropsMedia, Context) ->
replace_file_mime_ok(File, RscId, Props, PropsMedia, Opts, Context) ->
case RscId == insert_rsc orelse z_acl:rsc_editable(RscId, Context) orelse not(m_rsc:p(RscId, is_authoritative, Context)) of
true ->
Mime = proplists:get_value(mime, PropsMedia),
Expand All @@ -302,6 +327,9 @@ replace_file(File, RscId, Props, PropsMedia, Context) ->
| PropsMedia
],

IsImport = proplists:is_defined(is_import, Opts),
NoTouch = proplists:is_defined(no_touch, Opts),

F = fun(Ctx) ->
Props1 = case proplists:is_defined(category, Props)
orelse proplists:is_defined(category_id, Props)
Expand All @@ -311,15 +339,20 @@ replace_file(File, RscId, Props, PropsMedia, Context) ->
end,
{ok, Id} = case RscId of
insert_rsc ->
m_rsc:insert(Props1, Ctx);
m_rsc_update:insert(Props1, Opts, Ctx);
_ ->
%% When the resource is in the media category, then move it to the correct sub-category depending
%% on the mime type of the uploaded file.
case rsc_is_media_cat(RscId, Context) of
true -> m_rsc:update(RscId, Props1, Context);
false -> m_rsc:touch(RscId, Context)
true ->
{ok, RscId} = m_rsc_update:update(RscId, Props1, Opts, Ctx);
false ->
case IsImport orelse NoTouch of
true -> nop;
false -> {ok, RscId} = m_rsc:touch(RscId, Ctx)
end
end,
z_db:delete(medium, RscId, Context),
z_db:delete(medium, RscId, Ctx),
{ok, RscId}
end,
case z_db:insert(medium, [{id, Id} | MediumRowProps], Ctx) of
Expand Down
30 changes: 26 additions & 4 deletions src/models/m_rsc_update.erl
Expand Up @@ -148,6 +148,7 @@ update(Id, Props, true, Context) ->
update(Id, Props, Options, Context) when is_integer(Id) orelse Id == insert_rsc ->
EscapeTexts = proplists:get_value(escape_texts, Options, true),
AclCheck = proplists:get_value(acl_check, Options, true),
IsImport = proplists:is_defined(is_import, Options),
IsEditable = Id == insert_rsc orelse z_acl:rsc_editable(Id, Context) orelse not(AclCheck),

case IsEditable of
Expand Down Expand Up @@ -236,18 +237,33 @@ update(Id, Props, Options, Context) when is_integer(Id) orelse Id == insert_rsc

UpdateProps1 = [
{version, z_db:q1("select version+1 from rsc where id = $1", [RscId], Ctx)},
{modifier_id, z_acl:user(Ctx)},
{modified, calendar:local_time()}
{modifier_id, z_acl:user(Ctx)}
| UpdateProps
],

% Optionally fetch the created date if this is an import of a resource
UpdateProps2 = case imported_prop(IsImport, created, AtomProps, undefined) of
undefined -> UpdateProps1;
CreatedDT -> [{created, CreatedDT}|UpdateProps1]
end,

UpdateProps3 = case IsImport of
false ->
[{modified, calendar:local_time()} | UpdateProps2 ];
true ->
case imported_prop(IsImport, created, AtomProps, undefined) of
undefined -> UpdateProps2;
ModifiedDT -> [{modified, ModifiedDT}|UpdateProps2]
end
end,

% Allow the update props to be modified.
{Changed, UpdatePropsN} = z_notifier:foldr(#rsc_update{
action=case Id of insert_rsc -> insert; _ -> update end,
id=RscId,
props=BeforeProps
},
{false, UpdateProps1},
{false, UpdateProps3},
Ctx),
UpdatePropsN1 = case proplists:get_value(category_id, UpdatePropsN) of
undefined ->
Expand Down Expand Up @@ -309,7 +325,7 @@ update(Id, Props, Options, Context) when is_integer(Id) orelse Id == insert_rsc

% Return the updated or inserted id
{ok, NewId};
{rollback, {Why, _} = Er} ->
{rollback, {_Why, _} = Er} ->
throw(Er)
end;
false ->
Expand All @@ -321,6 +337,12 @@ update(Id, Props, Options, Context) when is_integer(Id) orelse Id == insert_rsc
end.


imported_prop(false, _, _, Default) ->
Default;
imported_prop(true, Prop, Props, Default) ->
proplists:get_value(Prop, Props, Default).


%% @doc Check if the update will change the data in the database
%% @spec is_changed(Current, Props) -> bool()
is_changed(Current, Props) ->
Expand Down

0 comments on commit 15d13db

Please sign in to comment.