Skip to content
This repository has been archived by the owner on Jul 12, 2023. It is now read-only.

Commit

Permalink
Add export importers to the admin console (#1085)
Browse files Browse the repository at this point in the history
* Add export importers to the admin console

* Remove unused error

* Add and fix tests

* Tick ticks
  • Loading branch information
sethvargo authored Oct 15, 2020
1 parent 847eab9 commit 5ddd4aa
Show file tree
Hide file tree
Showing 17 changed files with 677 additions and 219 deletions.
5 changes: 4 additions & 1 deletion internal/admin/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,10 @@ func (c *Config) RenderTemplate(w http.ResponseWriter, tmpl string, p TemplateMa
fmt.Sprintf("%s/%s.html", c.TemplatePath, c.BotFile),
}

t, err := template.ParseFiles(files...)
t, err := template.
New(tmpl).
Funcs(TemplateFuncMap).
ParseFiles(files...)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
fmt.Fprint(w, err)
Expand Down
15 changes: 15 additions & 0 deletions internal/admin/controller.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,17 @@
// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, softwar
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package admin

import (
Expand All @@ -16,4 +30,5 @@ type Controller interface {
func ErrorPage(c *gin.Context, messages ...string) {
log.Printf("error: %v", messages)
c.HTML(http.StatusOK, "error", gin.H{"error": messages})
c.Abort()
}
70 changes: 70 additions & 0 deletions internal/admin/exportimporters/form.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, softwar
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// Package exportimporters is part of the admin system.
package exportimporters

import (
"github.com/google/exposure-notifications-server/internal/admin"
"github.com/google/exposure-notifications-server/internal/exportimport/model"
)

type formData struct {
IndexFile string `form:"index_file"`
ExportRoot string `form:"export_root"`
Region string `form:"region"`

// FromDate and FromTime are combined into FromTimestamp.
FromDate string `form:"from_date"`
FromTime string `form:"from_time"`

// ThruDate and ThruTime are combined into ThruTimestamp.
ThruDate string `form:"thru_date"`
ThruTime string `form:"thru_time"`
}

// BuildExportImporterModel populates and mutates the given model with form
// data. It overwrites any form data that's present.
func (f *formData) BuildExportImporterModel(c *model.ExportImport) error {
from, err := admin.CombineDateAndTime(f.FromDate, f.FromTime)
if err != nil {
return err
}
thru, err := admin.CombineDateAndTime(f.ThruDate, f.ThruTime)
if err != nil {
return err
}

if val := f.IndexFile; val != "" {
c.IndexFile = val
}

if val := f.ExportRoot; val != "" {
c.ExportRoot = val
}

if val := f.Region; val != "" {
c.Region = val
}

if !from.IsZero() {
c.From = from
}

if !thru.IsZero() {
c.Thru = &thru
}

return nil
}
85 changes: 85 additions & 0 deletions internal/admin/exportimporters/save.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, softwar
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package exportimporters

import (
"fmt"
"net/http"
"strconv"

"github.com/gin-gonic/gin"
"github.com/google/exposure-notifications-server/internal/admin"
exportimportdatabase "github.com/google/exposure-notifications-server/internal/exportimport/database"
exportimportmodel "github.com/google/exposure-notifications-server/internal/exportimport/model"
"github.com/google/exposure-notifications-server/internal/serverenv"
)

type saveController struct {
config *admin.Config
env *serverenv.ServerEnv
}

func NewSave(c *admin.Config, env *serverenv.ServerEnv) admin.Controller {
return &saveController{config: c, env: env}
}

func (v *saveController) Execute(c *gin.Context) {
var form formData
if err := c.Bind(&form); err != nil {
admin.ErrorPage(c, err.Error())
return
}

ctx := c.Request.Context()
m := admin.TemplateMap{}

db := exportimportdatabase.New(v.env.Database())
model := new(exportimportmodel.ExportImport)

idRaw := c.Param("id")
if idRaw != "" && idRaw != "0" {
id, err := strconv.ParseInt(idRaw, 10, 64)
if err != nil {
admin.ErrorPage(c, "failed to to parse `id` param.")
return
}

model, err = db.GetConfig(ctx, id)
if err != nil {
admin.ErrorPage(c, fmt.Sprintf("failed to load export importer config: %s", err))
return
}
}

if err := form.BuildExportImporterModel(model); err != nil {
admin.ErrorPage(c, fmt.Sprintf("failed to build export importer config: %s", err))
return
}

fn := db.AddConfig
if model.ID != 0 {
fn = db.UpdateConfig
}

if err := fn(ctx, model); err != nil {
admin.ErrorPage(c, fmt.Sprintf("failed to write export importer config: %s", err))
return
}

m.AddSuccess("Successfully updated export importer config!")
m["model"] = model
c.HTML(http.StatusOK, "export-importer", m)
c.Abort()
}
62 changes: 62 additions & 0 deletions internal/admin/exportimporters/view.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, softwar
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package exportimporters

import (
"fmt"
"net/http"
"strconv"

"github.com/gin-gonic/gin"
"github.com/google/exposure-notifications-server/internal/admin"
exportimportdatabase "github.com/google/exposure-notifications-server/internal/exportimport/database"
exportimportmodel "github.com/google/exposure-notifications-server/internal/exportimport/model"
"github.com/google/exposure-notifications-server/internal/serverenv"
)

type viewController struct {
config *admin.Config
env *serverenv.ServerEnv
}

func NewView(c *admin.Config, env *serverenv.ServerEnv) admin.Controller {
return &viewController{config: c, env: env}
}

func (v *viewController) Execute(c *gin.Context) {
ctx := c.Request.Context()

db := exportimportdatabase.New(v.env.Database())
model := new(exportimportmodel.ExportImport)

if idRaw := c.Param("id"); idRaw != "" && idRaw != "0" {
id, err := strconv.ParseInt(idRaw, 10, 64)
if err != nil {
admin.ErrorPage(c, fmt.Sprintf("Failed to parse `id` param: %s", err))
return
}

model, err = db.GetConfig(ctx, id)
if err != nil {
admin.ErrorPage(c, fmt.Sprintf("Failed to load export importer config: %s", err))
return
}
}

m := make(admin.TemplateMap)
m["model"] = model
c.HTML(http.StatusOK, "export-importer", m)
c.Abort()
}
46 changes: 46 additions & 0 deletions internal/admin/exportimporters/view_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, softwar
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package exportimporters

import (
"net/http/httptest"
"testing"

"github.com/google/exposure-notifications-server/internal/admin"
exportimportmodel "github.com/google/exposure-notifications-server/internal/exportimport/model"
)

func TestRenderSignatureInfo(t *testing.T) {
// Hello developer!
// If this test fails, it's likely that you changed something in
// internal/authorizedapp/model/
// And whatever you changed is used in the
// tools/admin-console/templates/siginfo.html
// That is what caused the test failure.
m := admin.TemplateMap{}
model := new(exportimportmodel.ExportImport)
m["model"] = model

recorder := httptest.NewRecorder()
config := admin.Config{
TemplatePath: "../../../tools/admin-console/templates",
TopFile: "top",
BotFile: "bottom",
}
err := config.RenderTemplate(recorder, "export-importer", m)
if err != nil {
t.Fatalf("error rendering template: %v", err)
}
}
22 changes: 15 additions & 7 deletions internal/admin/index/index.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (
"github.com/google/exposure-notifications-server/internal/admin"
aadb "github.com/google/exposure-notifications-server/internal/authorizedapp/database"
exdb "github.com/google/exposure-notifications-server/internal/export/database"
exportimportdatabase "github.com/google/exposure-notifications-server/internal/exportimport/database"
"github.com/google/exposure-notifications-server/internal/serverenv"
hadb "github.com/google/exposure-notifications-server/internal/verification/database"
)
Expand All @@ -39,35 +40,42 @@ func (h *indexHandler) Execute(c *gin.Context) {
ctx := c.Request.Context()
m := admin.TemplateMap{}

db := h.env.Database()

// Load authorized apps for index.
db := aadb.New(h.env.Database())
apps, err := db.ListAuthorizedApps(ctx)
apps, err := aadb.New(db).ListAuthorizedApps(ctx)
if err != nil {
admin.ErrorPage(c, err.Error())
return
}
m["apps"] = apps

// Load health authorities.
haDB := hadb.New(h.env.Database())
has, err := haDB.ListAllHealthAuthoritiesWithoutKeys(ctx)
has, err := hadb.New(db).ListAllHealthAuthoritiesWithoutKeys(ctx)
if err != nil {
admin.ErrorPage(c, err.Error())
return
}
m["healthauthorities"] = has

// Load export configurations.
exportDB := exdb.New(h.env.Database())
exports, err := exportDB.GetAllExportConfigs(ctx)
exports, err := exdb.New(db).GetAllExportConfigs(ctx)
if err != nil {
admin.ErrorPage(c, err.Error())
return
}
m["exports"] = exports

// Load export importer configurations.
exportImporters, err := exportimportdatabase.New(db).ListConfigs(ctx)
if err != nil {
admin.ErrorPage(c, err.Error())
return
}
m["exportImporters"] = exportImporters

// Load SignatureInfos
sigInfos, err := exportDB.ListAllSigntureInfos(ctx)
sigInfos, err := exdb.New(db).ListAllSigntureInfos(ctx)
if err != nil {
admin.ErrorPage(c, err.Error())
return
Expand Down
Loading

0 comments on commit 5ddd4aa

Please sign in to comment.