/src/install/z_install_data.erl

http://github.com/zotonic/zotonic · Erlang · 304 lines · 212 code · 49 blank · 43 comment · 6 complexity · 754219aa56cd64d1be4158a19f375fa3 MD5 · raw file

  1. %% @author Marc Worrell <marc@worrell.nl>
  2. %% @copyright 2009-2016 Marc Worrell, Arjan Scherpenisse
  3. %%
  4. %% @doc Initialize the database with start data.
  5. %% Copyright 2009-2016 Marc Worrell, Arjan Scherpenisse
  6. %%
  7. %% Licensed under the Apache License, Version 2.0 (the "License");
  8. %% you may not use this file except in compliance with the License.
  9. %% You may obtain a copy of the License at
  10. %%
  11. %% http://www.apache.org/licenses/LICENSE-2.0
  12. %%
  13. %% Unless required by applicable law or agreed to in writing, software
  14. %% distributed under the License is distributed on an "AS IS" BASIS,
  15. %% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  16. %% See the License for the specific language governing permissions and
  17. %% limitations under the License.
  18. -module(z_install_data).
  19. -author("Marc Worrell <marc@worrell.nl").
  20. %% interface functions
  21. -export([
  22. install/2,
  23. install_category/1,
  24. install_modules/1
  25. ]).
  26. -include_lib("zotonic.hrl").
  27. %% @doc Insert boot data into the database.
  28. %% @spec install(Host::atom(), Connection) -> ok
  29. install(Site, Context) ->
  30. lager:info("~p: Install start.", [Site]),
  31. ok = install_category(Context),
  32. ok = install_rsc(Context),
  33. ok = install_identity(Context),
  34. ok = install_predicate(Context),
  35. ok = install_skeleton_modules(Context),
  36. z_db:equery("SELECT setval('rsc_id_seq', m) FROM (select 1 + max(id) as m from rsc) sub", Context),
  37. lager:info("~p: Install done.", [Site]),
  38. ok.
  39. %% @doc Install all modules for the site.
  40. %% The list of modules is read from either the site config file,
  41. %% under the key <tt>install_modules</tt>.
  42. -spec install_modules(#context{}) -> ok.
  43. install_modules(Context) ->
  44. Site = z_context:site(Context),
  45. {ok, Config} = z_sites_manager:get_site_config(Site),
  46. Modules = [Site | proplists:get_value(install_modules, Config, [])],
  47. [install_module(M, Context) || M <- Modules],
  48. ok.
  49. %% @doc Install all skeleton modules for the site.
  50. %% If the <tt>install_modules</tt> is not defined then the standard list
  51. %% of modules from the skeleton is installed.
  52. -spec install_skeleton_modules(#context{}) -> ok.
  53. install_skeleton_modules(Context) ->
  54. Site = Context#context.site,
  55. {ok, Config} = z_sites_manager:get_site_config(Site),
  56. case proplists:get_value(install_modules, Config, []) of
  57. [] ->
  58. install_module({skeleton, proplists:get_value(skeleton, Config)}, Context),
  59. ok;
  60. _ ->
  61. ok
  62. end.
  63. install_module({skeleton, undefined}, _C) ->
  64. ok;
  65. install_module({skeleton, S}, C) ->
  66. [install_module(M, C) || M <- get_skeleton_modules(S)];
  67. install_module(M, Context) when is_atom(M); is_binary(M); is_list(M) ->
  68. case z_db:equery("update module set is_active = true where name = $1", [M], Context) of
  69. {ok, 1} = R ->
  70. R;
  71. {ok, 0} ->
  72. {ok, 1} = z_db:equery("insert into module (name, is_active) values ($1, true)", [M], Context)
  73. end.
  74. -spec get_skeleton_modules(Skeleton::atom()) -> list().
  75. get_skeleton_modules(empty) ->
  76. [
  77. mod_base,
  78. mod_menu,
  79. mod_oauth,
  80. mod_search,
  81. mod_oembed,
  82. mod_signal,
  83. mod_mqtt,
  84. mod_logging,
  85. mod_l10n,
  86. mod_authentication,
  87. mod_acl_adminonly,
  88. mod_editor_tinymce,
  89. mod_admin,
  90. mod_admin_category,
  91. mod_admin_config,
  92. mod_admin_identity,
  93. mod_admin_modules,
  94. mod_admin_predicate,
  95. mod_media_exif
  96. ];
  97. get_skeleton_modules(blog) ->
  98. [
  99. mod_base,
  100. mod_base_site,
  101. mod_menu,
  102. mod_oauth,
  103. mod_search,
  104. mod_oembed,
  105. mod_atom_feed,
  106. mod_translation,
  107. mod_signal,
  108. mod_logging,
  109. mod_mqtt,
  110. mod_l10n,
  111. mod_seo,
  112. mod_seo_sitemap,
  113. mod_authentication,
  114. mod_acl_adminonly,
  115. mod_editor_tinymce,
  116. mod_admin,
  117. mod_admin_category,
  118. mod_admin_config,
  119. mod_admin_identity,
  120. mod_admin_modules,
  121. mod_admin_predicate,
  122. mod_media_exif,
  123. mod_comment,
  124. mod_bootstrap
  125. ];
  126. get_skeleton_modules(_) ->
  127. %% nodb | undefined | OtherUnknown -> []
  128. [].
  129. install_category(C) ->
  130. lager:info("Inserting categories"),
  131. %% The egg has to lay a fk-checked chicken here, so the insertion order is sensitive.
  132. %% 1. Insert the categories "meta" and "category"
  133. {ok, 2} = z_db:equery("
  134. insert into hierarchy (name, id, parent_id, nr, lvl, lft, rght)
  135. values
  136. ('$category', 115, null, 90000000, 1, 90000000, 92000000),
  137. ('$category', 116, null, 91000000, 2, 91000000, 91000000)
  138. ", C),
  139. %% make "category" a sub-category of "meta"
  140. {ok, 1} = z_db:equery("update hierarchy set parent_id = 115 where id = 116", C),
  141. %% "http://purl.org/dc/terms/DCMIType" ?
  142. {ok, 1} = z_db:equery("
  143. insert into rsc (id, is_protected, visible_for, category_id, name, uri, props)
  144. values (116, true, 0, 116, 'category', $1, $2)
  145. ", [ undefined,
  146. ?DB_PROPS([{title, {trans, [{en, <<"Category">>}, {nl, <<"Categorie">>}]}}])
  147. ], C),
  148. {ok, 1} = z_db:equery("
  149. insert into rsc (id, is_protected, visible_for, category_id, name, uri, props)
  150. values (115, true, 0, 116, 'meta', $1, $2)
  151. ", [ undefined,
  152. ?DB_PROPS([{title, {trans, [{en, <<"Meta">>}, {nl, <<"Meta">>}]}}])
  153. ], C),
  154. %% Now that we have the category "category" we can insert all other categories.
  155. Cats = [
  156. {101,undefined, 1,1,1,1, other, true, undefined, [{title, {trans, [{en, <<"Uncategorized">>}, {nl, <<"Zonder categorie">>}]}}] },
  157. {104,undefined, 2,1,2,4, text, false, "http://purl.org/dc/dcmitype/Text", [{title, {trans, [{en, <<"Text">>}, {nl, <<"Tekst">>}]}}] },
  158. {106,104, 3,2,3,3, article, false, undefined, [{title, {trans, [{en, <<"Article">>}, {nl, <<"Artikel">>}]}}] },
  159. {109,106,4,3,4,4, news, false, undefined, [{title, {trans, [{en, <<"News">>}, {nl, <<"Nieuws">>}]}}] },
  160. {102,undefined, 5,1,5,5, person, true, undefined, [{title, {trans, [{en, <<"Person">>}, {nl, <<"Persoon">>}]}}] },
  161. {119,undefined, 6,1,6,7, location, false, undefined, [{title, {trans, [{en, <<"Location">>}, {nl, <<"Locatie">>}]}}] },
  162. {107,119, 7,2,7,7, website, false, undefined, [{title, {trans, [{en, <<"Website">>}, {nl, <<"Website">>}]}}] },
  163. {108, undefined, 8,1,8,8, event, false, "http://purl.org/dc/dcmitype/Event", [{title, {trans, [{en, <<"Event">>}, {nl, <<"Evenement">>}]}}] },
  164. {103,undefined, 9,1,9,9, artifact, false, "http://purl.org/dc/dcmitype/PhysicalObject",[{title, {trans, [{en, <<"Artifact">>}, {nl, <<"Artefact">>}]}}] },
  165. {110,undefined, 10,1,10,14, media, true, "http://purl.org/dc/dcmitype/Image", [{title, {trans, [{en, <<"Media">>}, {nl, <<"Media">>}]}}] },
  166. {111,110, 11,2,11,11, image, true, "http://purl.org/dc/dcmitype/StillImage", [{title, {trans, [{en, <<"Image">>}, {nl, <<"Afbeelding">>}]}}] },
  167. {112,110, 12,2,12,12, video, true, "http://purl.org/dc/dcmitype/MovingImage", [{title, {trans, [{en, <<"Video">>}, {nl, <<"Video">>}]}}] },
  168. {113,110, 13,2,13,13, audio, true, "http://purl.org/dc/dcmitype/Sound", [{title, {trans, [{en, <<"Audio">>}, {nl, <<"Geluid">>}]}}] },
  169. {114,110, 14,2,14,14, document, true, undefined, [{title, {trans, [{en, <<"Document">>}, {nl, <<"Document">>}]}}] },
  170. {120,undefined, 15,1,15,16, collection, false, "http://purl.org/dc/dcmitype/Collection", [{title, {trans, [{en, <<"Collection">>}, {nl, <<"Collectie">>}]}}] },
  171. {121,120, 16,2,16,16, 'query', false, "http://purl.org/dc/dcmitype/Dataset", [{title, {trans, [{en, <<"Search query">>}, {nl, <<"Zoekopdracht">>}]}}] },
  172. {122,undefined, 17,1,17,18, categorization,true,undefined, [{title, {trans, [{en, <<"Categorization">>}, {nl, <<"Categorisatie">>}]}}] },
  173. {123,122, 18,2,18,18, keyword, true, undefined, [{title, {trans, [{en, <<"Keyword">>}, {nl, <<"Trefwoord">>}]}}] },
  174. % 115. Meta (see above)
  175. % 116. Category (see above)
  176. {117,115, 92,2,92,92, predicate, true, undefined, [{title, {trans, [{en, <<"Predicate">>}, {nl, <<"Predikaat">>}]}}] }
  177. % Next id: 124
  178. ],
  179. InsertCatFun = fun({Id, ParentId, Nr, Lvl, Left, Right, Name, Protected, Uri, Props}) ->
  180. {ok, 1} = z_db:equery("
  181. insert into rsc (id, visible_for, category_id, is_protected, name, uri, props)
  182. values ($1, 0, 116, $2, $3, $4, $5)
  183. ", [ Id, Protected, Name, Uri, ?DB_PROPS(Props) ], C),
  184. {ok, 1} = z_db:equery("
  185. insert into hierarchy (name, id, parent_id, nr, lvl, lft, rght)
  186. values ('$category', $1, $2, $3, $4, $5, $6)",
  187. [Id, ParentId, Nr*1000000, Lvl, Left*1000000, Right*1000000-1], C)
  188. end,
  189. lists:foreach(InsertCatFun, Cats),
  190. ok.
  191. %% @doc Install some initial resources, most important is the system administrator
  192. %% @todo Add the hostname to the uri
  193. install_rsc(C) ->
  194. lager:info("Inserting base resources (admin, etc.)"),
  195. Rsc = [
  196. % id vsfr cat protect name, props
  197. [ 1, 0, 102, true, "administrator", ?DB_PROPS([{title,<<"Site Administrator">>}]) ]
  198. ],
  199. [ {ok,1} = z_db:equery("
  200. insert into rsc (id, visible_for, category_id, is_protected, name, props)
  201. values ($1, $2, $3, $4, $5, $6)
  202. ", R, C) || R <- Rsc ],
  203. {ok, _} = z_db:equery("update rsc set creator_id = 1, modifier_id = 1, is_published = true", C),
  204. ok.
  205. %% @doc Install the admin user as an user. Uses the hard coded password "admin" when no password defined in the environment.
  206. install_identity(C) ->
  207. lager:info("Inserting username for the admin"),
  208. Hash = m_identity:hash([]),
  209. {ok, 1} = z_db:equery("
  210. insert into identity (rsc_id, type, key, is_unique, propb)
  211. values (1, 'username_pw', 'admin', true, $1)", [{term, Hash}], C),
  212. ok.
  213. %% @doc Install some initial predicates, this list should be extended with common and useful predicates
  214. %% See http://dublincore.org/documents/dcmi-terms/
  215. %% @todo Extend and check this list. Add allowed from/to categories.
  216. install_predicate(C) ->
  217. lager:info("Inserting predicates"),
  218. Preds = [
  219. % id protect name uri props
  220. [ 300, true, "about", "http://www.w3.org/1999/02/22-rdf-syntax-ns#about", ?DB_PROPS([{reversed, false},{title, {trans, [{en,"About"}, {nl,"Over"}]}}])],
  221. [ 301, true, "author", "http://purl.org/dc/terms/creator", ?DB_PROPS([{reversed, false},{title, {trans, [{en,"Author"}, {nl,"Auteur"}]}}])],
  222. [ 303, true, "relation", "http://purl.org/dc/terms/relation", ?DB_PROPS([{reversed, false},{title, {trans, [{en,"Relation"}, {nl,"Relatie"}]}}])],
  223. [ 304, true, "depiction","http://xmlns.com/foaf/0.1/depiction", ?DB_PROPS([{reversed, false},{title, {trans, [{en,"Depiction"},{nl,"Afbeelding"}]}}])],
  224. [ 308, true, "subject", "http://purl.org/dc/elements/1.1/subject", ?DB_PROPS([{reversed, false},{title, {trans, [{en,"Keyword"}, {nl,"Trefwoord"}]}}])],
  225. [ 309, true, "hasdocument", "http://zotonic.net/predicate/hasDocument", ?DB_PROPS([{reversed, false},{title, {trans, [{en,"Document"}, {nl,"Document"}]}}])],
  226. [ 310, true, "haspart", "http://purl.org/dc/terms/hasPart", ?DB_PROPS([{reversed, false},{title, {trans, [{en,"Contains"}, {nl,"Bevat"}]}}])]
  227. ],
  228. CatId = z_db:q1("select id from rsc where name = 'predicate'", C),
  229. [ {ok,1} = z_db:equery("
  230. insert into rsc (id, visible_for, is_protected, name, uri, props, category_id, is_published, creator_id, modifier_id)
  231. values ($1, 0, $2, $3, $4, $5, $6, true, 1, 1)
  232. ", R ++ [CatId], C) || R <- Preds],
  233. ObjSubj = [
  234. [300, true, 104], % text -> about -> _
  235. [301, false, 102], % _ -> author -> person
  236. [304, false, 110], % _ -> depiction -> image
  237. [308, true, 104], % text -> subject -> _
  238. [308, true, 102], % person -> subject -> _
  239. [308, true, 119], % location -> subject -> _
  240. [308, true, 108], % event -> subject -> _
  241. [308, true, 103], % artifact -> subject -> _
  242. [308, true, 110], % media -> subject -> _
  243. [308, true, 114], % collection -> subject -> _
  244. [308, false, 123], % _ -> subject -> keyword
  245. [309, true, 102], % person -> document -> _
  246. [309, true, 103], % artifact -> document -> _
  247. [309, true, 104], % text -> document -> _
  248. [309, true, 119], % location -> document -> _
  249. [309, false, 114], % _ -> document -> media
  250. [310, true, 120] % collection -> haspart -> _
  251. ],
  252. [ {ok, 1} = z_db:equery("
  253. insert into predicate_category (predicate_id, is_subject, category_id)
  254. values ($1, $2, $3)", OS, C) || OS <- ObjSubj ],
  255. ok.