diff options
-rw-r--r-- | shard/lib/app/chat.ex | 5 | ||||
-rw-r--r-- | shard/lib/app/directory.ex | 164 | ||||
-rw-r--r-- | shard/lib/app/identity.ex | 14 | ||||
-rw-r--r-- | shard/lib/manager.ex | 8 | ||||
-rw-r--r-- | shardweb/assets/css/app.css | 8 | ||||
-rw-r--r-- | shardweb/lib/controllers/chat_controller.ex | 8 | ||||
-rw-r--r-- | shardweb/lib/controllers/directory_controller.ex | 63 | ||||
-rw-r--r-- | shardweb/lib/controllers/identity_controller.ex | 4 | ||||
-rw-r--r-- | shardweb/lib/router.ex | 3 | ||||
-rw-r--r-- | shardweb/lib/shard_uri.ex | 42 | ||||
-rw-r--r-- | shardweb/lib/templates/chat/chat.html.eex | 4 | ||||
-rw-r--r-- | shardweb/lib/templates/directory/view.html.eex | 75 | ||||
-rw-r--r-- | shardweb/lib/templates/identity/view.html.eex | 3 | ||||
-rw-r--r-- | shardweb/lib/templates/layout/app.html.eex | 8 | ||||
-rw-r--r-- | shardweb/lib/templates/page/shard_list.html.eex | 8 | ||||
-rw-r--r-- | shardweb/lib/views/directory_view.ex | 2 |
16 files changed, 334 insertions, 85 deletions
diff --git a/shard/lib/app/chat.ex b/shard/lib/app/chat.ex index 2a3872b..405210b 100644 --- a/shard/lib/app/chat.ex +++ b/shard/lib/app/chat.ex @@ -39,6 +39,7 @@ defmodule SApp.Chat do defimpl Shard.Manifest do def module(_m), do: SApp.Chat + def is_valid?(_m), do: true end end @@ -60,6 +61,10 @@ defmodule SApp.Chat do defimpl Shard.Manifest do def module(_m), do: SApp.Chat + def is_valid?(m) do + Enum.all?(m.pk_list, &(byte_size(&1)==32)) + and m.pk_list == m.pk_list |> Enum.sort |> Enum.uniq + end end end diff --git a/shard/lib/app/directory.ex b/shard/lib/app/directory.ex index f4b5a0b..96e3a2b 100644 --- a/shard/lib/app/directory.ex +++ b/shard/lib/app/directory.ex @@ -1,8 +1,9 @@ defmodule SApp.Directory do @moduledoc""" Shard application for a directory of other shards. + Items can be stored (they become dependencies) or just links for possible reference. - TODO: use MST for file list instead of plain list + TODO: use MST for item list instead of plain list """ use GenServer @@ -19,11 +20,16 @@ defmodule SApp.Directory do defimpl Shard.Manifest do def module(_m), do: SApp.Directory + def is_valid?(m) do + is_boolean(m.public) + and is_binary(m.name) + and byte_size(m.owner) == 32 + end end end defmodule State do - defstruct [:owner, :public, :name, :manifest, :id, :netgroup, :files, :revfiles] + defstruct [:owner, :public, :name, :manifest, :id, :netgroup, :items, :revitems] end def start_link(manifest) do @@ -35,7 +41,7 @@ defmodule SApp.Directory do id = SData.term_hash manifest Shard.Manager.dispatch_to(id, nil, self()) - files = case Shard.Manager.load_state(id) do + items = case Shard.Manager.load_state(id) do nil -> SData.SignRev.new %{} st -> st @@ -46,37 +52,37 @@ defmodule SApp.Directory do end SNet.Group.init_lookup(netgroup, self()) - revfiles = for {n, m} <- SData.SignRev.get(files), into: %{}, do: {m, n} + revitems = for {n, m} <- SData.SignRev.get(items), into: %{}, do: {m, n} {:ok, %State{ owner: owner, public: public, name: name, manifest: manifest, id: id, netgroup: netgroup, - files: files, revfiles: revfiles}} + items: items, revitems: revitems}} end def handle_call(:manifest, _from, state) do {:reply, state.manifest, state} end - def handle_call(:get_files, _from, state) do - {:reply, SData.SignRev.get(state.files), state} + def handle_call(:get_items, _from, state) do + {:reply, SData.SignRev.get(state.items), state} end - def handle_call({:add_file, name, manifest}, _from, state) do + def handle_call({:add_item, name, manifest, stored}, _from, state) do if Shard.Keys.have_sk?(state.owner) do - dict = SData.SignRev.get(state.files) - if dict[name] != nil and dict[name] != manifest do + dict = SData.SignRev.get(state.items) + if dict[name] != nil and elem(dict[name], 0) != manifest do {:reply, :exists_already, state} else - dict = Map.put(dict, name, manifest) - GenServer.cast(Shard.Manager, {:dep_list, state.id, Map.values(dict)}) - {:ok, st2} = SData.SignRev.set(state.files, dict, state.owner) + dict = Map.put(dict, name, {manifest, stored}) + {:ok, st2} = SData.SignRev.set(state.items, dict, state.owner) Shard.Manager.save_state(state.id, st2) state = %{state | - files: st2, - revfiles: Map.put(state.revfiles, manifest, name) + items: st2, + revitems: Map.put(state.revitems, manifest, name) } bcast_state(state) + send_deps(state) {:reply, :ok, state} end else @@ -84,20 +90,41 @@ defmodule SApp.Directory do end end - def handle_call({:rm_file, name}, _from, state) do + def handle_call({:rm_item, item}, _from, state) do if Shard.Keys.have_sk?(state.owner) do - dict = SData.SignRev.get(state.files) - if dict[name] == nil do - {:reply, :not_found, state} - else - state = put_in(state.revfiles, Map.delete(state.revfiles, dict[name])) - dict = Map.delete(dict, name) - GenServer.cast(Shard.Manager, {:dep_list, state.id, Map.values(dict)}) - {:ok, st2} = SData.SignRev.set(state.files, dict, state.owner) - Shard.Manager.save_state(state.id, st2) - state = put_in(state.files, st2) - bcast_state(state) - {:reply, :ok, state} + dict = SData.SignRev.get(state.items) + case find(state, dict, item) do + {name, manifest} -> + state = put_in(state.revitems, Map.delete(state.revitems, manifest)) + dict = Map.delete(dict, name) + {:ok, st2} = SData.SignRev.set(state.items, dict, state.owner) + Shard.Manager.save_state(state.id, st2) + state = put_in(state.items, st2) + bcast_state(state) + send_deps(state) + {:reply, :ok, state} + nil -> + {:reply, :not_found, state} + end + else + {:reply, :impossible, state} + end + end + + def handle_call({:set_stored, item, stored}, _from, state) do + if Shard.Keys.have_sk?(state.owner) do + dict = SData.SignRev.get(state.items) + case find(state, dict, item) do + {name, manifest} -> + dict = Map.put(dict, name, {manifest, stored}) + {:ok, st2} = SData.SignRev.set(state.items, dict, state.owner) + Shard.Manager.save_state(state.id, st2) + state = put_in(state.items, st2) + bcast_state(state) + send_deps(state) + {:reply, :ok, state} + nil -> + {:reply, :not_found, state} end else {:reply, :impossible, state} @@ -105,23 +132,22 @@ defmodule SApp.Directory do end def handle_call({:read, name}, _from, state) do - dict = SData.SignRev.get(state.files) + dict = SData.SignRev.get(state.items) {:reply, dict[name], state} end def handle_call({:find, manifest}, _from, state) do - {:reply, state.revfiles[manifest], state} + {:reply, state.revitems[manifest], state} end def handle_cast(:send_deps, state) do - dict = SData.SignRev.get(state.files) - GenServer.cast(Shard.Manager, {:dep_list, state.id, Map.values(dict)}) + send_deps(state) {:noreply, state} end def handle_cast({:interested, peer_pid, auth}, state) do if SNet.Group.in_group?(state.netgroup, peer_pid, auth) do - SNet.Manager.send_pid(peer_pid, {state.id, nil, {:update, SData.SignRev.signed(state.files), true}}) + SNet.Manager.send_pid(peer_pid, {state.id, nil, {:update, SData.SignRev.signed(state.items), true}}) end {:noreply, state} end @@ -132,17 +158,17 @@ defmodule SApp.Directory do else state = case msg do {:update, signed, ask_reply} when signed != nil -> - state = case SData.SignRev.merge(state.files, signed, state.pk) do - {true, newfiles} -> - Shard.Manager.save_state(state.id, newfiles) - state = put_in(state.files, newfiles) + state = case SData.SignRev.merge(state.items, signed, state.pk) do + {true, newitems} -> + Shard.Manager.save_state(state.id, newitems) + state = put_in(state.items, newitems) bcast_state(state, [conn_pid]) state {false, _} -> state end if ask_reply do - SNet.Manager.send_pid(conn_pid, {state.id, nil, {:update, SData.SignRev.signed(state.files), false}}) + SNet.Manager.send_pid(conn_pid, {state.id, nil, {:update, SData.SignRev.signed(state.items), false}}) end state _ -> state @@ -151,53 +177,83 @@ defmodule SApp.Directory do end end + defp find(state, dict, item) do + cond do + dict[item] != nil -> + {manifest, _} = dict[item] + {item, manifest} + state.revitems[item] != nil -> + name = state.revitems[item] + {name, item} + true -> + nil + end + end + defp bcast_state(state, exclude \\ []) do - msg = {state.id, nil, {:update, SData.SignRev.signed(state.files), false}} + msg = {state.id, nil, {:update, SData.SignRev.signed(state.items), false}} SNet.Group.broadcast(state.netgroup, msg, exclude_pid: exclude) end + defp send_deps(state) do + dict = SData.SignRev.get(state.items) + IO.puts("items: #{inspect dict}") + deps = for {_, {m, stored}} <- dict, stored, do: m + IO.puts("stored: #{inspect deps}") + GenServer.cast(Shard.Manager, {:dep_list, state.id, deps}) + end + # ================ # PUBLIC INTERFACE # ================ @doc""" - Return list of files stored in this directory. + Return list of items stored in this directory. - Returns a dictionnary of %{name => manifest}. + Returns a dictionnary of %{name => {manifest, stored?}}. """ - def get_files(pid) do - GenServer.call(pid, :get_files) + def get_items(pid) do + GenServer.call(pid, :get_items) end @doc""" - Return the manifest of file with a given name in directory, or nil if not found. + Return the manifest of item with a given name in directory, or nil if not found. - Equivalent to get_files(pid)[name] but better. + Equivalent to get_items(pid)[name] but better. """ def read(pid, name) do GenServer.call(pid, {:read, name}) end @doc""" - Find a file in the directory by its manifest. Returns name if found or nil if not found. + Find an item in the directory by its manifest. Returns name if found or nil if not found. """ def find(pid, manifest) do GenServer.call(pid, {:find, manifest}) end @doc""" - Add a file to this directory. A file is a name for a shard manifest. - A file added to a directory becomes a dependency of the directory, i.e. - if the directory is pinned then all files inside are pinned as well. + Add an item to this directory. An item is a name for a shard manifest. + An item added to a directory becomes a dependency of the directory, i.e. + if the directory is pinned then all items inside are pinned as well. + """ + def add_item(pid, name, manifest, stored \\ true) do + GenServer.call(pid, {:add_item, name, manifest, stored}) + end + + @doc""" + Remove a named item from this directory. + Argument can be either a manifest or the name of an item. """ - def add_file(pid, name, manifest) do - GenServer.call(pid, {:add_file, name, manifest}) + def rm_item(pid, item) do + GenServer.call(pid, {:rm_item, item}) end @doc""" - Remove a named file from this directory. + Set an item as stored or not stored. + Argument can be either a manifest or the name of an item. """ - def rm_file(pid, name) do - GenServer.call(pid, {:rm_file, name}) + def set_stored(pid, item, stored) do + GenServer.call(pid, {:set_stored, item, stored}) end end diff --git a/shard/lib/app/identity.ex b/shard/lib/app/identity.ex index 69bed93..59a4b90 100644 --- a/shard/lib/app/identity.ex +++ b/shard/lib/app/identity.ex @@ -27,6 +27,9 @@ defmodule SApp.Identity do defimpl Shard.Manifest do def module(_m), do: SApp.Identity + def is_valid?(m) do + byte_size(m.pk) == 32 + end end end @@ -79,9 +82,16 @@ defmodule SApp.Identity do end def handle_cast(:send_deps, state) do - # TODO: collections + deps = if Shard.Keys.have_sk?(state.pk) do + [ + %SApp.Directory.Manifest{owner: state.pk, public: true, name: "collection"}, + %SApp.Directory.Manifest{owner: state.pk, public: false, name: "collection"} + ] + else + [] + end - GenServer.cast(Shard.Manager, {:dep_list, state.id, []}) + GenServer.cast(Shard.Manager, {:dep_list, state.id, deps}) {:noreply, state} end diff --git a/shard/lib/manager.ex b/shard/lib/manager.ex index 990bcea..c178e2f 100644 --- a/shard/lib/manager.ex +++ b/shard/lib/manager.ex @@ -17,6 +17,11 @@ defprotocol Shard.Manifest do Get the module in question. """ def module(manifest) + + @doc""" + Check if manifest is valid + """ + def is_valid?(manifest) end defmodule Shard.Manager do @@ -189,6 +194,8 @@ defmodule Shard.Manager do end defp find_or_start(state, shard_id, manifest) do + true = Shard.Manifest.is_valid?(manifest) + case :dets.lookup(@shard_db, shard_id) do [] -> :dets.insert(@shard_db, {shard_id, manifest, cached(), nil}) @@ -200,6 +207,7 @@ defmodule Shard.Manager do case :ets.lookup(:shard_procs, {shard_id, nil}) do [] -> {:ok, pid} = apply(Shard.Manifest.module(manifest), :start_link, [manifest]) + GenServer.cast(pid, :send_deps) :ets.insert(:shard_procs, {{shard_id, nil}, pid}) state = Map.put(state, pid, {shard_id, nil}) {pid, state} diff --git a/shardweb/assets/css/app.css b/shardweb/assets/css/app.css index 93cba41..140f32e 100644 --- a/shardweb/assets/css/app.css +++ b/shardweb/assets/css/app.css @@ -13,3 +13,11 @@ .conn_establishing { color: #999; } + +.shard_uri { + display: inline-block; + max-width: 400px; + overflow: hidden; + text-overflow:ellipsis; + font: monospace; +} diff --git a/shardweb/lib/controllers/chat_controller.ex b/shardweb/lib/controllers/chat_controller.ex index 080ee61..1ca66d4 100644 --- a/shardweb/lib/controllers/chat_controller.ex +++ b/shardweb/lib/controllers/chat_controller.ex @@ -4,11 +4,13 @@ defmodule ShardWeb.ChatController do def chat(conn, %{"chan" => chan}) do conn = put_gon(conn, chat_channel: "chat:" <> chan) - shard = %SApp.Chat.Manifest{channel: chan} |> SData.term_hash + manifest = %SApp.Chat.Manifest{channel: chan} + shard = manifest |> SData.term_hash render conn, "chat.html", public: true, shard: shard, + manifest: manifest, chan: chan end @@ -37,10 +39,12 @@ defmodule ShardWeb.ChatController do |> Enum.map(&SApp.Identity.get_nick/1) |> Enum.join(", ") - shard = [conn.assigns.pk | pk_list] |> SApp.Chat.PrivChat.Manifest.new |> SData.term_hash + manifest = [conn.assigns.pk | pk_list] |> SApp.Chat.PrivChat.Manifest.new + shard = manifest |> SData.term_hash render conn, "chat.html", public: false, + manifest: manifest, shard: shard, nicks: name else diff --git a/shardweb/lib/controllers/directory_controller.ex b/shardweb/lib/controllers/directory_controller.ex index 1e3a0b0..10fdec2 100644 --- a/shardweb/lib/controllers/directory_controller.ex +++ b/shardweb/lib/controllers/directory_controller.ex @@ -1,29 +1,64 @@ defmodule ShardWeb.DirectoryController do use ShardWeb, :controller - def view_pub(conn, %{"owner" => owner, "name" => name}) do - owner = Base.decode16! owner - shard = %SApp.Directory.Manifest{public: true, owner: owner, name: name} - pid = Shard.Manager.find_or_start shard + def view_pub(conn, args) do + view(conn, true, args) + end - render conn, "view.html", - public: true, - shard: shard, - pid: pid, - owner: owner, - name: name + def view_priv(conn, args) do + view(conn, false, args) end - def view_priv(conn, %{"owner" => owner, "name" => name}) do + def view(conn, public, %{"owner" => owner, "name" => name}=args) do owner = Base.decode16! owner - shard = %SApp.Directory.Manifest{public: false, owner: owner, name: name} - pid = Shard.Manager.find_or_start shard + manifest = %SApp.Directory.Manifest{public: public, owner: owner, name: name} + shard = SData.term_hash manifest + pid = Shard.Manager.find_or_start manifest render conn, "view.html", - public: false, + public: public, shard: shard, + manifest: manifest, pid: pid, owner: owner, name: name end + + def dir_add(conn, %{"dir_name" => dir_name, "dir_public" => dir_public, "add_name" => add_name, "add_uri" => add_uri, "add_stored" => add_stored}) do + dir_public = (dir_public == "true") + + manifest = %SApp.Directory.Manifest{public: dir_public, owner: conn.assigns.pk, name: dir_name} + shard = SData.term_hash manifest + pid = Shard.Manager.find_or_start manifest + + item_manifest = ShardURI.to_manifest(add_uri) + SApp.Directory.add_item(pid, add_name, item_manifest, (add_stored == "yes")) + + redirect conn, to: directory_path(conn, (if dir_public do :view_pub else :view_priv end), conn.assigns.pk|>Base.encode16, dir_name) + end + + def dir_rm(conn, %{"dir_name" => dir_name, "dir_public" => dir_public, "item_name" => rm_name}) do + dir_public = (dir_public == "true") + + manifest = %SApp.Directory.Manifest{public: dir_public, owner: conn.assigns.pk, name: dir_name} + shard = SData.term_hash manifest + pid = Shard.Manager.find_or_start manifest + + SApp.Directory.rm_item(pid, rm_name) + + redirect conn, to: directory_path(conn, (if dir_public do :view_pub else :view_priv end), conn.assigns.pk|>Base.encode16, dir_name) + end + + def dir_set_stored(conn, %{"dir_name" => dir_name, "dir_public" => dir_public, "item_name" => item_name, "item_stored" => item_stored}) do + dir_public = (dir_public == "true") + item_stored = (item_stored == "true") + + manifest = %SApp.Directory.Manifest{public: dir_public, owner: conn.assigns.pk, name: dir_name} + shard = SData.term_hash manifest + pid = Shard.Manager.find_or_start manifest + + SApp.Directory.set_stored(pid, item_name, item_stored) + + redirect conn, to: directory_path(conn, (if dir_public do :view_pub else :view_priv end), conn.assigns.pk|>Base.encode16, dir_name) + end end diff --git a/shardweb/lib/controllers/identity_controller.ex b/shardweb/lib/controllers/identity_controller.ex index 962a888..7452453 100644 --- a/shardweb/lib/controllers/identity_controller.ex +++ b/shardweb/lib/controllers/identity_controller.ex @@ -11,7 +11,8 @@ defmodule ShardWeb.IdentityController do def view(conn, %{"pk" => pk}) do {:ok, pk} = Base.decode16(pk) - shard = %SApp.Identity.Manifest{pk: pk} |> SData.term_hash + manifest = %SApp.Identity.Manifest{pk: pk} + shard = manifest |> SData.term_hash pid = Shard.Manager.find_proc shard if pid == nil do @@ -21,6 +22,7 @@ defmodule ShardWeb.IdentityController do view_pk: pk, view_nick: SApp.Identity.get_nick(pk), shard: shard, + manifest: manifest, pid: pid end end diff --git a/shardweb/lib/router.ex b/shardweb/lib/router.ex index 61f8209..3f78afd 100644 --- a/shardweb/lib/router.ex +++ b/shardweb/lib/router.ex @@ -31,6 +31,9 @@ defmodule ShardWeb.Router do get "/pub/:owner/:name", DirectoryController, :view_pub get "/priv/:owner/:name", DirectoryController, :view_priv + post "/dir/add", DirectoryController, :dir_add + post "/dir/rm", DirectoryController, :dir_rm + post "/dir/set_stored", DirectoryController, :dir_set_stored get "/chat/:chan", ChatController, :chat get "/pm/:people_list", ChatController, :privchat diff --git a/shardweb/lib/shard_uri.ex b/shardweb/lib/shard_uri.ex new file mode 100644 index 0000000..71c0904 --- /dev/null +++ b/shardweb/lib/shard_uri.ex @@ -0,0 +1,42 @@ +defmodule ShardURI do + @moduledoc""" + Convert Shard manifests to and from strings. + """ + + def from_manifest(m) do + case m do + %SApp.Chat.Manifest{channel: chan} -> "shard:chat:#{chan}" + %SApp.Chat.PrivChat.Manifest{pk_list: pk_list} -> + "shard:privchat:#{pk_list|>Enum.map(&Base.encode16/1)|>Enum.join(",")}" + %SApp.Identity.Manifest{pk: pk} -> + "shard:identity:#{pk|>Base.encode16}" + %SApp.Directory.Manifest{owner: owner, public: true, name: name} -> + "shard:dir:pub:#{owner|>Base.encode16}:#{name}" + %SApp.Directory.Manifest{owner: owner, public: false, name: name} -> + "shard:dir:priv:#{owner|>Base.encode16}:#{name}" + end + end + + def to_manifest(p) do + case p do + "shard:chat:" <> chan -> + %SApp.Chat.Manifest{channel: chan} + "shard:privchat:" <> pklist -> + pklist + |> String.split(",") + |> Enum.map(&parse_pk/1) + |> SApp.Chat.PrivChat.Manifest.new() + "shard:identity:" <> pk -> + %SApp.Identity.Manifest{pk: parse_pk pk} + "shard:dir:pub:" <> <<pk::bytes-size(64)>> <> ":" <> name -> + %SApp.Directory.Manifest{owner: parse_pk(pk), public: true, name: name} + "shard:dir:priv:" <> <<pk::bytes-size(64)>> <> ":" <> name -> + %SApp.Directory.Manifest{owner: parse_pk(pk), public: false, name: name} + end + end + + def parse_pk(pkstr) do + 64 = byte_size pkstr + Base.decode16! pkstr + end +end diff --git a/shardweb/lib/templates/chat/chat.html.eex b/shardweb/lib/templates/chat/chat.html.eex index 499e14d..947e4c3 100644 --- a/shardweb/lib/templates/chat/chat.html.eex +++ b/shardweb/lib/templates/chat/chat.html.eex @@ -4,11 +4,11 @@ <h1 class="page-header"> <%= if @public do %> #<%= @chan %> - <small>public chat room</small> <% else %> <%= @nicks %> - <small>private chat</small> <% end %> + <small class="shard_uri"><%= @manifest |> ShardURI.from_manifest %></small> + </h1> <ol class="breadcrumb"> diff --git a/shardweb/lib/templates/directory/view.html.eex b/shardweb/lib/templates/directory/view.html.eex index 43ded97..b4cbfaf 100644 --- a/shardweb/lib/templates/directory/view.html.eex +++ b/shardweb/lib/templates/directory/view.html.eex @@ -3,7 +3,7 @@ <div class="col-lg-12"> <h1 class="page-header"> <%= @name %> - <small>directory contents</small> + <small class="shard_uri"><%= @manifest |> ShardURI.from_manifest %></small> </h1> <ol class="breadcrumb"> @@ -18,6 +18,11 @@ </li> <li class="active"> <i class="fa fa-folder"></i> <%= @name %> + <%= if @public do %> + (public) + <% else %> + (private) + <% end %> </li> </ol> </div> @@ -30,18 +35,80 @@ <tr> <th>Name</th> <th>Shard</th> - <th>Id</th> + <th style="width: 150px"></th> + <th>URI</th> </tr> - <%= for {name, manifest} <- dir_contents(@conn, @shard) do %> + <%= for {name, {manifest, stored}} <- dir_contents(@conn, @manifest) do %> <tr> <td> + <%= if stored do %> + <i class="fa fa-save"></i> + <% else %> + <i class="fa fa-link"></i> + <% end %> <strong><%= name %></strong> </td> <td> <%= render ShardWeb.PageView, "shard_entry.html", conn: @conn, manifest: manifest %> </td> - <td><small><%= (SData.term_hash manifest) |> Base.encode16 %></small></td> + <td> + <%= form_for @conn, directory_path(@conn, :dir_rm), [class: "form-inline", style: "display: inline"], fn f -> %> + <%= hidden_input f, :dir_name, value: @name %> + <%= hidden_input f, :dir_public, value: @public %> + <%= hidden_input f, :item_name, value: name %> + <%= submit "Remove", [class: "btn btn-xs btn-danger"] %> + <% end %> + <%= form_for @conn, directory_path(@conn, :dir_set_stored), [class: "form-inline", style: "display: inline"], fn f -> %> + <%= hidden_input f, :dir_name, value: @name %> + <%= hidden_input f, :dir_public, value: @public %> + <%= hidden_input f, :item_name, value: name %> + <%= hidden_input f, :item_stored, value: (if stored do "false" else "true" end) %> + <%= if stored do %> + <%= submit "Don't store", [class: "btn btn-xs btn-warning"] %> + <% else %> + <%= submit "Store", [class: "btn btn-xs btn-success"] %> + <% end %> + <% end %> + </td> + <td><small class="shard_uri"><%= manifest |> ShardURI.from_manifest %></small></td> </tr> <% end %> </table> +<%= if @owner == @pk do %> + <fieldset><legend>Add existing item</legend> + <%= form_for @conn, directory_path(@conn, :dir_add), [class: "form-horizontal"], fn f -> %> + <%= hidden_input f, :dir_name, value: @name %> + <%= hidden_input f, :dir_public, value: @public %> + <div class="form-group"> + <%= label :add_name, "Name:", class: ["col-sm-2 control-label"] %> + <div class="col-sm-10"> + <%= text_input f, :add_name, [class: "form-control", value: ""] %> + </div> + </div> + <div class="form-group"> + <%= label :add_uri, "URI:", class: ["col-sm-2 control-label"] %> + <div class="col-sm-10"> + <%= text_input f, :add_uri, [class: "form-control", placeholder: "example: shard:identity:xxx"] %> + </div> + </div> + <div class="form-group"> + <label class="col-sm-2 control-label">Stored?</label> + <div class="col-sm-10"> + <div class="radio"> + <label><%= radio_button f, :add_stored, "yes" %>Stored <i class="fa fa-save"></i></label> + </div> + <div class="radio"> + <label><%= radio_button f, :add_stored, "no" %>Linked <i class="fa fa-link"></i></label> + </div> + </div> + </div> + + <div class="form-group"> + <div class="col-sm-offset-2 col-sm-10"> + <%= submit "Add", [class: "btn btn-default"] %> + </div> + </div> + <% end %> + </fieldset> +<% end %> diff --git a/shardweb/lib/templates/identity/view.html.eex b/shardweb/lib/templates/identity/view.html.eex index 3fb5a3f..c5dfaf2 100644 --- a/shardweb/lib/templates/identity/view.html.eex +++ b/shardweb/lib/templates/identity/view.html.eex @@ -2,7 +2,8 @@ <div class="row"> <div class="col-lg-12"> <h1 class="page-header"> - <%= @view_nick %> <small><%= @view_pk |> Base.encode16 %></small> + <%= @view_nick %> + <small class="shard_uri"><%= @manifest |> ShardURI.from_manifest %></small> </h1> <ol class="breadcrumb"> <li> diff --git a/shardweb/lib/templates/layout/app.html.eex b/shardweb/lib/templates/layout/app.html.eex index 1310131..bd5e3b2 100644 --- a/shardweb/lib/templates/layout/app.html.eex +++ b/shardweb/lib/templates/layout/app.html.eex @@ -127,6 +127,14 @@ <!-- Sidebar Menu Items - These collapse to the responsive navigation menu on small screens --> <div class="collapse navbar-collapse navbar-ex1-collapse"> <ul class="nav navbar-nav side-nav"> + + <li class="<%= if @view_module == ShardWeb.Directoryview and @view_template == "view.html" do "active" else "" end %>"> + <a href="<%= directory_path(@conn, :view_pub, Base.encode16(@pk), "collection") %>"><i class="fa fa-fw fa-globe"></i> My public stuff</a> + </li> + <li class="<%= if @view_module == ShardWeb.Directoryview and @view_template == "view.html" do "active" else "" end %>"> + <a href="<%= directory_path(@conn, :view_priv, Base.encode16(@pk), "collection") %>"><i class="fa fa-fw fa-folder"></i> My private stuff</a> + </li> + <li class="<%= if @view_module == ShardWeb.ChatView and @view_template == "chat.html" and @public do "active" else "" end %>"> <a href="javascript:;" data-toggle="collapse" data-target="#demo"><i class="fa fa-fw fa-hashtag"></i> Chat rooms <i class="fa fa-fw fa-caret-down"></i></a> <ul id="demo" class="<%= if not (@view_module == ShardWeb.ChatView and @view_template == "chat.html" and @public) do "collapse" else "" end %>"> diff --git a/shardweb/lib/templates/page/shard_list.html.eex b/shardweb/lib/templates/page/shard_list.html.eex index dd846d8..3fffef7 100644 --- a/shardweb/lib/templates/page/shard_list.html.eex +++ b/shardweb/lib/templates/page/shard_list.html.eex @@ -23,21 +23,21 @@ <tr> <th></th> <th>Shard</th> - <th>Id</th> + <th>URI</th> </tr> - <%= for {id, manifest, why_have_it} <- shard_list() do %> + <%= for {_id, manifest, why_have_it} <- shard_list() do %> <tr> <td> <%= case why_have_it do %> <% {:cached, _} -> %><span class="label label-warning">cache</span> <% {:pinned, _, _} -> %><span class="label label-success">pinned</span> - <% {:req, a, _} -> %><span class="label label-default">req (<%= MapSet.size(a) %>)</span> + <% {:req, a, _} -> %><span class="label label-success">req (<%= MapSet.size(a) %>)</span> <% end %> </td> <td> <%= render "shard_entry.html", conn: @conn, manifest: manifest, pk: @pk %> </td> - <td><small><%= id |> Base.encode16 %></small></td> + <td><small class="shard_uri"><%= manifest |> ShardURI.from_manifest %></small></td> </tr> <% end %> </table> diff --git a/shardweb/lib/views/directory_view.ex b/shardweb/lib/views/directory_view.ex index acbd950..ea31482 100644 --- a/shardweb/lib/views/directory_view.ex +++ b/shardweb/lib/views/directory_view.ex @@ -4,6 +4,6 @@ defmodule ShardWeb.DirectoryView do def dir_contents(_conn, manifest) do IO.puts(inspect manifest) pid = Shard.Manager.find_or_start manifest - SApp.Directory.get_files pid + SApp.Directory.get_items pid end end |