Skip to content
Snippets Groups Projects
Commit 787c9e0a authored by Romain Foucault's avatar Romain Foucault Committed by GitHub
Browse files

Merge pull request #253 from nono/cozy-bar

Make it easy to inject a cozy-bar in a client-side app
parents fc7bde81 2883eb3f
No related branches found
No related tags found
No related merge requests found
......@@ -13,3 +13,7 @@
name ./js/cozy-client.js
url https://raw.githubusercontent.com/cozy/cozy-client-js/v0.0.4/dist/cozy-client.js
sha256 c5ff7a39ba3f716137a35538b08b794fdbc573ddd4241236a1583243f2aa61e1
name ./js/cozy-bar.js
url https://raw.githubusercontent.com/cozy/cozy-bar/3.0.0-beta3/dist/cozy-bar.min.js
sha256 a8a1fa9f9e1a18ae7e1f23cbc66d45c4f8a54858ae8a385314291768b50eaa7e
......@@ -94,6 +94,7 @@ it as a template and will insert the relevant values.
- `{{.Token}}` will be replaced by the token for the application.
- `{{.Domain}}` will be replaced by the stack hostname.
- `{{.Locale}}` will be replaced by the locale for the instance.
- `{{.CozyBar}}` will be replaced by the JavaScript to inject the cozy-bar.
So, the `index.html` should probably looks like:
......@@ -103,10 +104,10 @@ So, the `index.html` should probably looks like:
<head>
<meta charset="utf-8">
<title>My Awesome App for Cozy</title>
<link rel="stylesheet" src="{{.Domain}}/settings/theme.css">
<link rel="stylesheet" src="//{{.Domain}}/settings/theme.css">
<link rel="stylesheet" src="my-app.css">
<script defer src="{{.Domain}}/assets/js/cozy-client.js"></script>
<script defer src="{{.Domain}}/assets/js/cozy-bar.js"></script>
<script defer src="//{{.Domain}}/assets/js/cozy-client.js"></script>
{{.CozyBar}}
<script defer src="my-app.js"></script>
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
......@@ -128,7 +129,6 @@ document.addEventListener('DOMContentLoaded', () => {
cozyURL: app.dataset.cozyStack,
token: app.dataset.token
})
cozy.bar(app)
})
// ...
......
......@@ -3,8 +3,10 @@
package apps
import (
"fmt"
"net/http"
"net/url"
"text/template"
log "github.com/Sirupsen/logrus"
"github.com/cozy/cozy-stack/pkg/apps"
......@@ -13,6 +15,36 @@ import (
"github.com/labstack/echo"
)
// JSMimeType is the content-type for javascript
const JSMimeType = "application/javascript"
// CozyBarJS is the JavaScript used to initialize a cozy-bar
const CozyBarJS = `document.addEventListener('DOMContentLoaded', () => {
cozy.bar.init({
appName: '%s',
iconPath: '%s',
lang: '%s'
})
})`
// InitCozyBarJS returns a JavaScript that initializes the cozy-bar with
// options from the manifest of the application
func InitCozyBarJS(c echo.Context) error {
instance := middlewares.GetInstance(c)
slug := c.Param("slug")
man, err := apps.GetBySlug(instance, slug)
if err != nil {
return err
}
appName := template.JSEscapeString(man.Name)
iconPath := template.JSEscapeString(man.Icon)
lang := template.JSEscapeString(instance.Locale)
body := fmt.Sprintf(CozyBarJS, appName, iconPath, lang)
return c.Blob(http.StatusOK, JSMimeType, []byte(body))
}
// InstallOrUpdateHandler handles all POST /:slug request and tries to install
// or update the application with the given Source.
func InstallOrUpdateHandler(c echo.Context) error {
......@@ -70,6 +102,7 @@ func ListHandler(c echo.Context) error {
func Routes(router *echo.Group) {
router.GET("/", ListHandler)
router.POST("/:slug", InstallOrUpdateHandler)
router.GET("/:slug/init-cozy-bar.js", InitCozyBarJS)
}
func wrapAppsError(err error) error {
......
......@@ -67,6 +67,8 @@ func createFile(dir, filename, content string) error {
func installMiniApp() error {
manifest = &apps.Manifest{
Name: "Mini",
Icon: "icon.png",
Slug: slug,
Source: "git://github.com/cozy/mini.git",
State: apps.Ready,
......@@ -76,6 +78,11 @@ func installMiniApp() error {
Index: "index.html",
Public: false,
},
"/bar": apps.Route{
Folder: "/bar",
Index: "index.html",
Public: false,
},
"/public": apps.Route{
Folder: "/public",
Index: "index.html",
......@@ -94,6 +101,11 @@ func installMiniApp() error {
if err != nil {
return err
}
bardir := path.Join(appdir, "bar")
_, err = vfs.Mkdir(testInstance, bardir, nil)
if err != nil {
return err
}
pubdir := path.Join(appdir, "public")
_, err = vfs.Mkdir(testInstance, pubdir, nil)
if err != nil {
......@@ -104,6 +116,10 @@ func installMiniApp() error {
if err != nil {
return err
}
err = createFile(bardir, "index.html", "{{.CozyBar}}")
if err != nil {
return err
}
err = createFile(appdir, "hello.html", "world {{.Token}}")
if err != nil {
return err
......@@ -174,6 +190,28 @@ func TestServe(t *testing.T) {
assertNotFound(t, "/public/hello.html")
}
func TestCozyBar(t *testing.T) {
assertAuthGet(t, "/bar/", "text/html", ``+
`<script defer src="//cozywithapps.example.net/assets/js/cozy-bar.js"></script>`+
`<script defer src="//cozywithapps.example.net/apps/mini/init-cozy-bar.js"></script>`)
expected := `document.addEventListener('DOMContentLoaded', () => {
cozy.bar.init({
appName: 'Mini',
iconPath: 'icon.png',
lang: 'en'
})
})`
req, _ := http.NewRequest("GET", ts.URL+"/apps/mini/init-cozy-bar.js", nil)
req.Host = domain
res, err := client.Do(req)
assert.NoError(t, err)
assert.Equal(t, 200, res.StatusCode)
assert.Equal(t, "application/javascript", res.Header.Get("Content-Type"))
body, _ := ioutil.ReadAll(res.Body)
assert.Equal(t, expected, string(body))
}
func TestServeAppsWithACode(t *testing.T) {
config.GetConfig().Subdomains = config.FlatSubdomains
appHost := "cozywithapps-mini.example.net"
......@@ -267,6 +305,7 @@ func TestMain(m *testing.M) {
c.SetCookie(cookie)
return c.HTML(http.StatusOK, "OK")
})
r.GET("/apps/:slug/init-cozy-bar.js", webApps.InitCozyBarJS)
router, err := web.CreateSubdomainProxy(r, webApps.Serve)
if err != nil {
fmt.Println(err)
......
package apps
import (
"bytes"
"html/template"
"io/ioutil"
"log"
......@@ -63,6 +64,23 @@ func tryAuthWithSessionCode(c echo.Context, i *instance.Instance, value string)
return c.Redirect(http.StatusFound, u.String())
}
var barTemplate = template.Must(template.New("cozy-bar").Parse(`` +
`<script defer src="//{{.Domain}}/assets/js/cozy-bar.js"></script>` +
`<script defer src="//{{.Domain}}/apps/{{.Slug}}/init-cozy-bar.js"></script>`,
))
func cozybar(i *instance.Instance, app *apps.Manifest) template.HTML {
buf := new(bytes.Buffer)
err := barTemplate.Execute(buf, echo.Map{
"Domain": i.Domain,
"Slug": app.Slug,
})
if err != nil {
return template.HTML("")
}
return template.HTML(buf.String()) // #nosec
}
func serveApp(c echo.Context, i *instance.Instance, app *apps.Manifest, vpath string) error {
route, file := app.FindRoute(vpath)
cfg := config.GetConfig()
......@@ -123,8 +141,9 @@ func serveApp(c echo.Context, i *instance.Instance, app *apps.Manifest, vpath st
res.Header().Set("Content-Type", doc.Mime)
res.WriteHeader(http.StatusOK)
return tmpl.Execute(res, echo.Map{
"Token": token,
"Domain": i.Domain,
"Locale": i.Locale,
"Token": token,
"Domain": i.Domain,
"Locale": i.Locale,
"CozyBar": cozybar(i, app),
})
}
Source diff could not be displayed: it is too large. Options to address this: view the blob.
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment