~tsileo/blobstash-pwa

970bad609050d5f3efdf8f209a1034bbe6e2ac26 — Thomas Sileo 2 years ago 6bc76be
Tweak and check in support
3 files changed, 134 insertions(+), 38 deletions(-)

M README.md
M app.lua
A templates/index.html
M README.md => README.md +31 -0
@@ 1,1 1,32 @@
# BlobStash PWA

<p align="center">
  <img 
    src="https://sos-ch-dk-2.exo.io/hexaninja/blobstash.png" 
    width="192" height="192" border="0" alt="microblog.pub">
</p>

## Features

 - Registers a web share target for images/pictures
   - Allows to upload pictures directly using the built-in Android sharing option
 - Location check in
   - Save GPS location with an optional place name in a DocStore collection

## Setup

```
$ git clone https://git.sr.ht/~tsileo/blobstash-pwa
```

In your `blobstash.yaml`:

```
 apps:
   - name: blobstash-pwa
     path: /path/to/cloned/blobstash-pwa
     username: user
     password: pass
```

Then go to `https://your-blobstash-instance.tld/api/apps/blobstash-pwa/`

M app.lua => app.lua +53 -38
@@ 1,55 1,70 @@
local template = require('template')
local router = require('router').new()
local ft = require('filetree')
local docstore = require('docstore')
local json = require('json')

router:get('/', function(params)
  app.response:write(template.render_string([[
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <title>BlobStash</title>
    <link rel="manifest" href="/api/apps/{{.app_id}}/manifest.json">
<script>
  if ('serviceWorker' in navigator) {
    navigator.serviceWorker.register('/api/apps/{{.app_id}}/service-worker.js')
  app.response:write(template.render("index.html", {app_id = blobstash.app_id}))
end)

router:post('/checkin', function(params)
  local form = app.request:form()
  local checkin = {
    ts = tonumber(form:get("location_ts")),
    lat = tonumber(form:get("location_lat")),
    lng = tonumber(form:get("location_lng")),
    name = form:get("location_name"),
    device_id = app.request:headers():get("User-Agent"),
  }
</script>
  </head>
  <body>
    <h2>BlobStash</h2>
    <p>This app only registers a sharing plugin.</p>
  </body>
</html>
  ]], {app_id = blobstash.app_id}))
  local col = docstore.col('gps_locations')
  col:insert(checkin)
  app.response:redirect("/api/apps/" .. blobstash.app_id .. "/")
end)

router:get('/manifest.json', function(params)
  app.response:headers():set("Content-Type", "application/json")
  app.response:write(template.render_string([[{
      "short_name": "BlobStash",
      "name": "BlobStash",
      "share_target": {
          "action": "/api/apps/{{.app_id}}/share-target",
          "enctype": "multipart/form-data",
          "method": "POST",
          "params": {"files": [{"name": "image", "accept": ["image/*"]}]}},
          "icons": [
                {"src": "https://sos-ch-dk-2.exo.io/hexaninja/blobstash.png", "sizes": "192x192", "type": "image/png"},
                {"src": "https://sos-ch-dk-2.exo.io/hexaninja/blobstash_512.png", "sizes": "512x512", "type": "image/png"}
           ],
           "start_url": "/api/apps/{{.app_id}}/",
           "background_color": "#ffffff",
           "display": "standalone",
           "scope": "/api/apps/{{.app_id}}/",
           "theme_color": "#ffffff"
       }]], {app_id = blobstash.app_id}))
  app.response:write(json.encode{
    short_name = "BlobStash",
    name = "BlobStash",
    share_target = {
      action = "/api/apps/" .. blobstash.app_id .. "/share-target",
      enctype = "multipart/form-data",
      method = "POST",
      params = {
        files = {
          {
            name = "image",
            accept = {"image/*"}
          },
        },
      },
    },
    icons = {
      {
        src = "https://sos-ch-dk-2.exo.io/hexaninja/blobstash.png",
        sizes  = "192x192",
        type = "image/png",
      },
      {
        src = "https://sos-ch-dk-2.exo.io/hexaninja/blobstash_512.png",
        sizes  = "512x512",
        type = "image/png",
      },
    },
    start_url = "/api/apps/" .. blobstash.app_id .. "/",
    background_color = "#ffffff",
    theme_color = "#ffffff",
    display = "standalone",
    scope = "/api/apps/" .. blobstash.app_id .. "/",
  })
end)

router:post("/share-target", function(params)
  local f = app.request:file('image')
  local new_parent, _ = ft.put_file_at({user_agent = "Android", message = "Uploaded " .. f.filename .. " via sharing"}, f.filename, f.contents, "Android", "/")
  app.response:write("OK")
  local commit = {user_agent = "Android", message = "Uploaded " .. f.filename .. " via sharing"}
  local new_parent, _ = ft.put_file_at(commit, f.filename, f.contents, "Android", "/")
  app.response:redirect("/api/apps/" .. blobstash.app_id .. "/")
end)

router:get("/service-worker.js", function(params)

A templates/index.html => templates/index.html +50 -0
@@ 0,0 1,50 @@
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta http-equiv="x-ua-compatible" content="ie=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
    <title>BlobStash</title>
    <link rel="manifest" href="/api/apps/{{.app_id}}/manifest.json" crossorigin="use-credentials">
<script>
  if ('serviceWorker' in navigator) {
    navigator.serviceWorker.register('/api/apps/{{.app_id}}/service-worker.js')
  }
</script>
  </head>
  <body>
    <h1>BlobStash</h1>
    <h2>Check in</h2>
    <form action="/api/apps/{{.app_id}}/checkin" method="POST">
     <a href="#" class="location_autofill">set location</a>
     <div>
     <input type="text" name="location_lat" id="location_lat" placeholder="latitude">
     <input type="text" name="location_lng" id="location_lng" placeholder="longitude">
     </div>
     <input type="hidden" name="location_ts" id="location_ts">
     <div>
     <input type="text" name="location_name" placeholder="location name (optional)">
     </div>
     <div>
     <input type="submit" value="check in">
     </div>
    </form>
    <h2>Share plugin</h2>
    <p>BlobStash should appear as a target when sharing images/pictures.</p>
    <script>
var askForLocation = function(ev) {
    ev.preventDefault();
    navigator.geolocation.getCurrentPosition(function(position) {
        console.log(position);
        document.getElementById("location_lat").value = position.coords.latitude;
        document.getElementById("location_lng").value = position.coords.longitude;
        document.getElementById("location_ts").value = Date.now();
    });
}
var items = document.getElementsByClassName("location_autofill")
for (var i = 0; i < items.length; i++) {
    items[i].addEventListener('click', askForLocation);
}
    </script>
  </body>
</html>