separate profile model from account model
This commit is contained in:
parent
f729160209
commit
c3271d7dcf
15 changed files with 152 additions and 83 deletions
|
|
@ -11,7 +11,6 @@ import (
|
||||||
validation "github.com/go-ozzo/ozzo-validation"
|
validation "github.com/go-ozzo/ozzo-validation"
|
||||||
|
|
||||||
"github.com/dhax/go-base/auth"
|
"github.com/dhax/go-base/auth"
|
||||||
"github.com/dhax/go-base/models"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// AccountStore defines database operations for account.
|
// AccountStore defines database operations for account.
|
||||||
|
|
@ -21,7 +20,6 @@ type AccountStore interface {
|
||||||
Delete(*auth.Account) error
|
Delete(*auth.Account) error
|
||||||
UpdateToken(*auth.Token) error
|
UpdateToken(*auth.Token) error
|
||||||
DeleteToken(*auth.Token) error
|
DeleteToken(*auth.Token) error
|
||||||
UpdateProfile(*models.Profile) error
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// AccountResource implements account managment handler.
|
// AccountResource implements account managment handler.
|
||||||
|
|
@ -46,7 +44,6 @@ func (rs *AccountResource) router() *chi.Mux {
|
||||||
r.Put("/", rs.updateToken)
|
r.Put("/", rs.updateToken)
|
||||||
r.Delete("/", rs.deleteToken)
|
r.Delete("/", rs.deleteToken)
|
||||||
})
|
})
|
||||||
r.Put("/profile", rs.updateProfile)
|
|
||||||
return r
|
return r
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -57,8 +54,7 @@ func (rs *AccountResource) accountCtx(next http.Handler) http.Handler {
|
||||||
account, err := rs.Store.Get(claims.ID)
|
account, err := rs.Store.Get(claims.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// account deleted while access token still valid
|
// account deleted while access token still valid
|
||||||
log(r).WithField("account", claims.Sub).Warn(err)
|
render.Render(w, r, ErrUnauthorized)
|
||||||
render.Render(w, r, ErrNotFound)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
ctx := context.WithValue(r.Context(), ctxAccount, account)
|
ctx := context.WithValue(r.Context(), ctxAccount, account)
|
||||||
|
|
@ -68,7 +64,8 @@ func (rs *AccountResource) accountCtx(next http.Handler) http.Handler {
|
||||||
|
|
||||||
type accountRequest struct {
|
type accountRequest struct {
|
||||||
*auth.Account
|
*auth.Account
|
||||||
// not really neccessary here as we limit updated database columns in store
|
// override protected data here, although not really neccessary here
|
||||||
|
// as we limit updated database columns in store as well
|
||||||
ProtectedID int `json:"id"`
|
ProtectedID int `json:"id"`
|
||||||
ProtectedActive bool `json:"active"`
|
ProtectedActive bool `json:"active"`
|
||||||
ProtectedRoles []string `json:"roles"`
|
ProtectedRoles []string `json:"roles"`
|
||||||
|
|
@ -174,44 +171,3 @@ func (rs *AccountResource) deleteToken(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
render.Respond(w, r, http.NoBody)
|
render.Respond(w, r, http.NoBody)
|
||||||
}
|
}
|
||||||
|
|
||||||
type profileRequest struct {
|
|
||||||
*models.Profile
|
|
||||||
ProtectedID int `json:"id"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *profileRequest) Bind(r *http.Request) error {
|
|
||||||
// d.ProtectedActive = true
|
|
||||||
// d.ProtectedRoles = []string{}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type profileResponse struct {
|
|
||||||
*models.Profile
|
|
||||||
}
|
|
||||||
|
|
||||||
func newProfileResponse(p *models.Profile) *profileResponse {
|
|
||||||
return &profileResponse{
|
|
||||||
Profile: p,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (rs *AccountResource) updateProfile(w http.ResponseWriter, r *http.Request) {
|
|
||||||
acc := r.Context().Value(ctxAccount).(*auth.Account)
|
|
||||||
data := &profileRequest{Profile: acc.Profile}
|
|
||||||
if err := render.Bind(r, data); err != nil {
|
|
||||||
render.Render(w, r, ErrInvalidRequest(err))
|
|
||||||
}
|
|
||||||
|
|
||||||
p := data.Profile
|
|
||||||
if err := rs.Store.UpdateProfile(p); err != nil {
|
|
||||||
switch err.(type) {
|
|
||||||
case validation.Errors:
|
|
||||||
render.Render(w, r, ErrValidation(err))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
render.Render(w, r, ErrRender(err))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
render.Respond(w, r, newProfileResponse(p))
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -15,11 +15,13 @@ type ctxKey int
|
||||||
|
|
||||||
const (
|
const (
|
||||||
ctxAccount ctxKey = iota
|
ctxAccount ctxKey = iota
|
||||||
|
ctxProfile
|
||||||
)
|
)
|
||||||
|
|
||||||
// API provides application resources and handlers.
|
// API provides application resources and handlers.
|
||||||
type API struct {
|
type API struct {
|
||||||
Account *AccountResource
|
Account *AccountResource
|
||||||
|
Profile *ProfileResource
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewAPI configures and returns application API.
|
// NewAPI configures and returns application API.
|
||||||
|
|
@ -27,8 +29,12 @@ func NewAPI(db *pg.DB) (*API, error) {
|
||||||
accountStore := database.NewAccountStore(db)
|
accountStore := database.NewAccountStore(db)
|
||||||
account := NewAccountResource(accountStore)
|
account := NewAccountResource(accountStore)
|
||||||
|
|
||||||
|
profileStore := database.NewProfileStore(db)
|
||||||
|
profile := NewProfileResource(profileStore)
|
||||||
|
|
||||||
api := &API{
|
api := &API{
|
||||||
Account: account,
|
Account: account,
|
||||||
|
Profile: profile,
|
||||||
}
|
}
|
||||||
return api, nil
|
return api, nil
|
||||||
}
|
}
|
||||||
|
|
@ -38,6 +44,7 @@ func (a *API) Router() *chi.Mux {
|
||||||
r := chi.NewRouter()
|
r := chi.NewRouter()
|
||||||
|
|
||||||
r.Mount("/account", a.Account.router())
|
r.Mount("/account", a.Account.router())
|
||||||
|
r.Mount("/profile", a.Profile.router())
|
||||||
|
|
||||||
return r
|
return r
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -70,9 +70,12 @@ func ErrRender(err error) render.Renderer {
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
// ErrBadRequest return status 400 Bad Request for malformed request body.
|
// ErrBadRequest returns status 400 Bad Request for malformed request body.
|
||||||
ErrBadRequest = &ErrResponse{HTTPStatusCode: http.StatusBadRequest, StatusText: http.StatusText(http.StatusBadRequest)}
|
ErrBadRequest = &ErrResponse{HTTPStatusCode: http.StatusBadRequest, StatusText: http.StatusText(http.StatusBadRequest)}
|
||||||
|
|
||||||
|
// ErrUnauthorized returns 401 Unauthorized.
|
||||||
|
ErrUnauthorized = &ErrResponse{HTTPStatusCode: http.StatusUnauthorized, StatusText: http.StatusText(http.StatusUnauthorized)}
|
||||||
|
|
||||||
// ErrNotFound returns status 404 Not Found for invalid resource request.
|
// ErrNotFound returns status 404 Not Found for invalid resource request.
|
||||||
ErrNotFound = &ErrResponse{HTTPStatusCode: http.StatusNotFound, StatusText: http.StatusText(http.StatusNotFound)}
|
ErrNotFound = &ErrResponse{HTTPStatusCode: http.StatusNotFound, StatusText: http.StatusText(http.StatusNotFound)}
|
||||||
|
|
||||||
|
|
|
||||||
95
api/app/profile.go
Normal file
95
api/app/profile.go
Normal file
|
|
@ -0,0 +1,95 @@
|
||||||
|
package app
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/dhax/go-base/auth"
|
||||||
|
"github.com/dhax/go-base/models"
|
||||||
|
"github.com/go-chi/chi"
|
||||||
|
"github.com/go-chi/render"
|
||||||
|
validation "github.com/go-ozzo/ozzo-validation"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ProfileStore defines database operations for a profile.
|
||||||
|
type ProfileStore interface {
|
||||||
|
Get(accountID int) (*models.Profile, error)
|
||||||
|
Update(p *models.Profile) error
|
||||||
|
}
|
||||||
|
|
||||||
|
// ProfileResource implements profile management handler.
|
||||||
|
type ProfileResource struct {
|
||||||
|
Store ProfileStore
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewProfileResource creates and returns a profile resource.
|
||||||
|
func NewProfileResource(store ProfileStore) *ProfileResource {
|
||||||
|
return &ProfileResource{
|
||||||
|
Store: store,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rs *ProfileResource) router() *chi.Mux {
|
||||||
|
r := chi.NewRouter()
|
||||||
|
r.Use(rs.profileCtx)
|
||||||
|
r.Get("/", rs.get)
|
||||||
|
r.Put("/", rs.update)
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rs *ProfileResource) profileCtx(next http.Handler) http.Handler {
|
||||||
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
claims := auth.ClaimsFromCtx(r.Context())
|
||||||
|
p, err := rs.Store.Get(claims.ID)
|
||||||
|
if err != nil {
|
||||||
|
log(r).WithField("profileCtx", claims.Sub).Error(err)
|
||||||
|
render.Render(w, r, ErrInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ctx := context.WithValue(r.Context(), ctxProfile, p)
|
||||||
|
next.ServeHTTP(w, r.WithContext(ctx))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
type profileRequest struct {
|
||||||
|
*models.Profile
|
||||||
|
ProtectedID int `json:"id"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *profileRequest) Bind(r *http.Request) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type profileResponse struct {
|
||||||
|
*models.Profile
|
||||||
|
}
|
||||||
|
|
||||||
|
func newProfileResponse(p *models.Profile) *profileResponse {
|
||||||
|
return &profileResponse{
|
||||||
|
Profile: p,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rs *ProfileResource) get(w http.ResponseWriter, r *http.Request) {
|
||||||
|
p := r.Context().Value(ctxProfile).(*models.Profile)
|
||||||
|
render.Respond(w, r, newProfileResponse(p))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rs *ProfileResource) update(w http.ResponseWriter, r *http.Request) {
|
||||||
|
p := r.Context().Value(ctxProfile).(*models.Profile)
|
||||||
|
data := &profileRequest{Profile: p}
|
||||||
|
if err := render.Bind(r, data); err != nil {
|
||||||
|
render.Render(w, r, ErrInvalidRequest(err))
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := rs.Store.Update(p); err != nil {
|
||||||
|
switch err.(type) {
|
||||||
|
case validation.Errors:
|
||||||
|
render.Render(w, r, ErrValidation(err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
render.Render(w, r, ErrRender(err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
render.Respond(w, r, newProfileResponse(p))
|
||||||
|
}
|
||||||
|
|
@ -5,7 +5,6 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/dhax/go-base/models"
|
|
||||||
"github.com/go-chi/jwtauth"
|
"github.com/go-chi/jwtauth"
|
||||||
validation "github.com/go-ozzo/ozzo-validation"
|
validation "github.com/go-ozzo/ozzo-validation"
|
||||||
"github.com/go-ozzo/ozzo-validation/is"
|
"github.com/go-ozzo/ozzo-validation/is"
|
||||||
|
|
@ -24,7 +23,6 @@ type Account struct {
|
||||||
Active bool `sql:",notnull" json:"active"`
|
Active bool `sql:",notnull" json:"active"`
|
||||||
Roles []string `pg:",array" json:"roles,omitempty"`
|
Roles []string `pg:",array" json:"roles,omitempty"`
|
||||||
|
|
||||||
Profile *models.Profile `json:"profile,omitempty"`
|
|
||||||
Token []*Token `json:"token,omitempty"`
|
Token []*Token `json:"token,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,7 @@ var (
|
||||||
|
|
||||||
func TestMain(m *testing.M) {
|
func TestMain(m *testing.M) {
|
||||||
viper.SetDefault("auth_login_token_length", 8)
|
viper.SetDefault("auth_login_token_length", 8)
|
||||||
viper.SetDefault("auth_login_token_expiry", 11)
|
viper.SetDefault("auth_login_token_expiry", "11m")
|
||||||
viper.SetDefault("auth_jwt_secret", "random")
|
viper.SetDefault("auth_jwt_secret", "random")
|
||||||
viper.SetDefault("log_level", "error")
|
viper.SetDefault("log_level", "error")
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@ func (s *AccountStore) Get(id int) (*auth.Account, error) {
|
||||||
a := auth.Account{ID: id}
|
a := auth.Account{ID: id}
|
||||||
err := s.db.Model(&a).
|
err := s.db.Model(&a).
|
||||||
Where("account.id = ?id").
|
Where("account.id = ?id").
|
||||||
Column("account.*", "Profile", "Token").
|
Column("account.*", "Token").
|
||||||
First()
|
First()
|
||||||
return &a, err
|
return &a, err
|
||||||
}
|
}
|
||||||
|
|
@ -67,9 +67,3 @@ func (s *AccountStore) DeleteToken(t *auth.Token) error {
|
||||||
err := s.db.Delete(t)
|
err := s.db.Delete(t)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdateProfile updates corresponding account profile.
|
|
||||||
func (s *AccountStore) UpdateProfile(p *models.Profile) error {
|
|
||||||
err := s.db.Update(p)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,6 @@ import (
|
||||||
const profileTable = `
|
const profileTable = `
|
||||||
CREATE TABLE profiles (
|
CREATE TABLE profiles (
|
||||||
id serial NOT NULL,
|
id serial NOT NULL,
|
||||||
created_at timestamp with time zone NOT NULL DEFAULT current_timestamp,
|
|
||||||
updated_at timestamp with time zone NOT NULL DEFAULT current_timestamp,
|
updated_at timestamp with time zone NOT NULL DEFAULT current_timestamp,
|
||||||
account_id int NOT NULL REFERENCES accounts(id),
|
account_id int NOT NULL REFERENCES accounts(id),
|
||||||
theme text NOT NULL DEFAULT 'default',
|
theme text NOT NULL DEFAULT 'default',
|
||||||
|
|
|
||||||
34
database/profileStore.go
Normal file
34
database/profileStore.go
Normal file
|
|
@ -0,0 +1,34 @@
|
||||||
|
package database
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/dhax/go-base/models"
|
||||||
|
"github.com/go-pg/pg"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ProfileStore implements database operations for profile management.
|
||||||
|
type ProfileStore struct {
|
||||||
|
db *pg.DB
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewProfileStore returns a ProfileStore implementation.
|
||||||
|
func NewProfileStore(db *pg.DB) *ProfileStore {
|
||||||
|
return &ProfileStore{
|
||||||
|
db: db,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get gets an profile by account ID.
|
||||||
|
func (s *ProfileStore) Get(accountID int) (*models.Profile, error) {
|
||||||
|
p := models.Profile{AccountID: accountID}
|
||||||
|
_, err := s.db.Model(&p).
|
||||||
|
Where("account_id = ?", accountID).
|
||||||
|
SelectOrInsert()
|
||||||
|
|
||||||
|
return &p, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update updates profile.
|
||||||
|
func (s *ProfileStore) Update(p *models.Profile) error {
|
||||||
|
err := s.db.Update(p)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
@ -10,9 +10,8 @@ import (
|
||||||
|
|
||||||
// Profile holds specific application settings linked to an Account.
|
// Profile holds specific application settings linked to an Account.
|
||||||
type Profile struct {
|
type Profile struct {
|
||||||
ID int `json:"id,omitempty"`
|
ID int `json:"-"`
|
||||||
AccountID int `json:"-"`
|
AccountID int `json:"-"`
|
||||||
CreatedAt time.Time `json:"created_at,omitempty"`
|
|
||||||
UpdatedAt time.Time `json:"updated_at,omitempty"`
|
UpdatedAt time.Time `json:"updated_at,omitempty"`
|
||||||
|
|
||||||
Theme string `json:"theme,omitempty"`
|
Theme string `json:"theme,omitempty"`
|
||||||
|
|
@ -20,11 +19,7 @@ type Profile struct {
|
||||||
|
|
||||||
// BeforeInsert hook executed before database insert operation.
|
// BeforeInsert hook executed before database insert operation.
|
||||||
func (p *Profile) BeforeInsert(db orm.DB) error {
|
func (p *Profile) BeforeInsert(db orm.DB) error {
|
||||||
now := time.Now()
|
p.UpdatedAt = time.Now()
|
||||||
if p.CreatedAt.IsZero() {
|
|
||||||
p.CreatedAt = now
|
|
||||||
p.UpdatedAt = now
|
|
||||||
}
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
File diff suppressed because one or more lines are too long
|
|
@ -1 +1 @@
|
||||||
!function(e){function n(r){if(t[r])return t[r].exports;var o=t[r]={i:r,l:!1,exports:{}};return e[r].call(o.exports,o,o.exports,n),o.l=!0,o.exports}var r=window.webpackJsonp;window.webpackJsonp=function(t,c,a){for(var f,u,i,d=0,b=[];d<t.length;d++)u=t[d],o[u]&&b.push(o[u][0]),o[u]=0;for(f in c)Object.prototype.hasOwnProperty.call(c,f)&&(e[f]=c[f]);for(r&&r(t,c,a);b.length;)b.shift()();if(a)for(d=0;d<a.length;d++)i=n(n.s=a[d]);return i};var t={},o={8:0};n.e=function(e){function r(){f.onerror=f.onload=null,clearTimeout(u);var n=o[e];0!==n&&(n&&n[1](new Error("Loading chunk "+e+" failed.")),o[e]=void 0)}var t=o[e];if(0===t)return new Promise(function(e){e()});if(t)return t[2];var c=new Promise(function(n,r){t=o[e]=[n,r]});t[2]=c;var a=document.getElementsByTagName("head")[0],f=document.createElement("script");f.type="text/javascript",f.charset="utf-8",f.async=!0,f.timeout=12e4,n.nc&&f.setAttribute("nonce",n.nc),f.src=n.p+"js/"+e+"."+{0:"d0eac5d7ffeb9ab42441",1:"cbd2396284cb24a3f034",2:"a2c6b5b1849e21bfcb82",3:"0926ebbc3cbecd74e6e3",4:"4bee4f55cde772260df1",5:"c59be07d40d0779615eb",6:"3f577f057549d7aec9ba",7:"8fd1b3f7b4e9ba060870"}[e]+".js";var u=setTimeout(r,12e4);return f.onerror=f.onload=r,a.appendChild(f),c},n.m=e,n.c=t,n.d=function(e,r,t){n.o(e,r)||Object.defineProperty(e,r,{configurable:!1,enumerable:!0,get:t})},n.n=function(e){var r=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(r,"a",r),r},n.o=function(e,n){return Object.prototype.hasOwnProperty.call(e,n)},n.p="/",n.oe=function(e){throw console.error(e),e}}([]);
|
!function(e){function n(r){if(t[r])return t[r].exports;var o=t[r]={i:r,l:!1,exports:{}};return e[r].call(o.exports,o,o.exports,n),o.l=!0,o.exports}var r=window.webpackJsonp;window.webpackJsonp=function(t,c,a){for(var u,f,i,d=0,s=[];d<t.length;d++)f=t[d],o[f]&&s.push(o[f][0]),o[f]=0;for(u in c)Object.prototype.hasOwnProperty.call(c,u)&&(e[u]=c[u]);for(r&&r(t,c,a);s.length;)s.shift()();if(a)for(d=0;d<a.length;d++)i=n(n.s=a[d]);return i};var t={},o={8:0};n.e=function(e){function r(){u.onerror=u.onload=null,clearTimeout(f);var n=o[e];0!==n&&(n&&n[1](new Error("Loading chunk "+e+" failed.")),o[e]=void 0)}var t=o[e];if(0===t)return new Promise(function(e){e()});if(t)return t[2];var c=new Promise(function(n,r){t=o[e]=[n,r]});t[2]=c;var a=document.getElementsByTagName("head")[0],u=document.createElement("script");u.type="text/javascript",u.charset="utf-8",u.async=!0,u.timeout=12e4,n.nc&&u.setAttribute("nonce",n.nc),u.src=n.p+"js/"+e+"."+{0:"d0eac5d7ffeb9ab42441",1:"cbd2396284cb24a3f034",2:"a2c6b5b1849e21bfcb82",3:"0926ebbc3cbecd74e6e3",4:"4bee4f55cde772260df1",5:"c59be07d40d0779615eb",6:"3f577f057549d7aec9ba",7:"fa5b5d78974d1828a266"}[e]+".js";var f=setTimeout(r,12e4);return u.onerror=u.onload=r,a.appendChild(u),c},n.m=e,n.c=t,n.d=function(e,r,t){n.o(e,r)||Object.defineProperty(e,r,{configurable:!1,enumerable:!0,get:t})},n.n=function(e){var r=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(r,"a",r),r},n.o=function(e,n){return Object.prototype.hasOwnProperty.call(e,n)},n.p="/",n.oe=function(e){throw console.error(e),e}}([]);
|
||||||
|
|
@ -1 +1 @@
|
||||||
"use strict";function setOfCachedUrls(e){return e.keys().then(function(e){return e.map(function(e){return e.url})}).then(function(e){return new Set(e)})}var precacheConfig=[["app.16d79810d85127430008b2c06589212d.css","bf841d47c7e84ffc085f7b9f98908fac"],["fonts/MaterialIcons-Regular.012cf6a.woff","012cf6a10129e2275d79d6adac7f3b02"],["index.html","7fad5de3f0e3206aad1dcab492cbd94b"],["js/0.d0eac5d7ffeb9ab42441.js","9943c8859c542bd228b1196db36e1c47"],["js/1.cbd2396284cb24a3f034.js","3c8428180a2e241cc9b02bf31a58d516"],["js/2.a2c6b5b1849e21bfcb82.js","7bf93828ce487e7aec18d3524757df2d"],["js/3.0926ebbc3cbecd74e6e3.js","dd4c759a1cf1328ade6b15c3a5f539d9"],["js/4.4bee4f55cde772260df1.js","1a6496f4b3fe20e541368fe959607c3c"],["js/5.c59be07d40d0779615eb.js","d9ddbd23627f3353c1d8fcfe1edab54b"],["js/app.js","692efac903fba4684b46dc88cf4bbfd2"],["js/manifest.js","b9f03819995e32e21890ef8ddc67f6eb"],["js/vendor.js","d0d6ed1c0632124351f39073feb9cbf0"],["statics/icons/apple-icon-152x152.png","da2b422e2895b9b9c1782a71b6be9d63"],["statics/icons/favicon-16x16.png","efb00e57304380d857603760600da5d5"],["statics/icons/favicon-32x32.png","2f9d7587924933c1912c342b190b53ca"],["statics/icons/icon-192x192.png","8c4120b4e88276badbc808e518572fad"],["statics/icons/icon-512x512.png","a13b2bd5261e2df374128df1aab93001"],["statics/icons/ms-icon-144x144.png","ed12d10fd0407eea42ccaf7af7991146"],["statics/manifest.json","ae10664f4d3a921479e6d4868ae0cdf5"],["statics/quasar-logo.png","3020c8ac2c2872dec7741e5948520093"]],cacheName="sw-precache-v3-my-quasar-app-"+(self.registration?self.registration.scope:""),ignoreUrlParametersMatching=[/^utm_/],addDirectoryIndex=function(e,n){var t=new URL(e);return"/"===t.pathname.slice(-1)&&(t.pathname+=n),t.toString()},cleanResponse=function(e){return e.redirected?("body"in e?Promise.resolve(e.body):e.blob()).then(function(n){return new Response(n,{headers:e.headers,status:e.status,statusText:e.statusText})}):Promise.resolve(e)},createCacheKey=function(e,n,t,a){var c=new URL(e);return a&&c.pathname.match(a)||(c.search+=(c.search?"&":"")+encodeURIComponent(n)+"="+encodeURIComponent(t)),c.toString()},isPathWhitelisted=function(e,n){if(0===e.length)return!0;var t=new URL(n).pathname;return e.some(function(e){return t.match(e)})},stripIgnoredUrlParameters=function(e,n){var t=new URL(e);return t.hash="",t.search=t.search.slice(1).split("&").map(function(e){return e.split("=")}).filter(function(e){return n.every(function(n){return!n.test(e[0])})}).map(function(e){return e.join("=")}).join("&"),t.toString()},hashParamName="_sw-precache",urlsToCacheKeys=new Map(precacheConfig.map(function(e){var n=e[0],t=e[1],a=new URL(n,self.location),c=createCacheKey(a,hashParamName,t,!1);return[a.toString(),c]}));self.addEventListener("install",function(e){e.waitUntil(caches.open(cacheName).then(function(e){return setOfCachedUrls(e).then(function(n){return Promise.all(Array.from(urlsToCacheKeys.values()).map(function(t){if(!n.has(t)){var a=new Request(t,{credentials:"same-origin"});return fetch(a).then(function(n){if(!n.ok)throw new Error("Request for "+t+" returned a response with status "+n.status);return cleanResponse(n).then(function(n){return e.put(t,n)})})}}))})}).then(function(){return self.skipWaiting()}))}),self.addEventListener("activate",function(e){var n=new Set(urlsToCacheKeys.values());e.waitUntil(caches.open(cacheName).then(function(e){return e.keys().then(function(t){return Promise.all(t.map(function(t){if(!n.has(t.url))return e.delete(t)}))})}).then(function(){return self.clients.claim()}))}),self.addEventListener("fetch",function(e){if("GET"===e.request.method){var n,t=stripIgnoredUrlParameters(e.request.url,ignoreUrlParametersMatching);(n=urlsToCacheKeys.has(t))||(t=addDirectoryIndex(t,"index.html"),n=urlsToCacheKeys.has(t));n&&e.respondWith(caches.open(cacheName).then(function(e){return e.match(urlsToCacheKeys.get(t)).then(function(e){if(e)return e;throw Error("The cached response that was expected is missing.")})}).catch(function(n){return console.warn('Couldn\'t serve response for "%s" from cache: %O',e.request.url,n),fetch(e.request)}))}});
|
"use strict";function setOfCachedUrls(e){return e.keys().then(function(e){return e.map(function(e){return e.url})}).then(function(e){return new Set(e)})}var precacheConfig=[["app.16d79810d85127430008b2c06589212d.css","bf841d47c7e84ffc085f7b9f98908fac"],["fonts/MaterialIcons-Regular.012cf6a.woff","012cf6a10129e2275d79d6adac7f3b02"],["index.html","7fad5de3f0e3206aad1dcab492cbd94b"],["js/0.d0eac5d7ffeb9ab42441.js","9943c8859c542bd228b1196db36e1c47"],["js/1.cbd2396284cb24a3f034.js","3c8428180a2e241cc9b02bf31a58d516"],["js/2.a2c6b5b1849e21bfcb82.js","7bf93828ce487e7aec18d3524757df2d"],["js/3.0926ebbc3cbecd74e6e3.js","dd4c759a1cf1328ade6b15c3a5f539d9"],["js/4.4bee4f55cde772260df1.js","1a6496f4b3fe20e541368fe959607c3c"],["js/5.c59be07d40d0779615eb.js","d9ddbd23627f3353c1d8fcfe1edab54b"],["js/app.js","662931fd9b0781405a1a3e8ee38a7179"],["js/manifest.js","06716c143ef039dc4764ec5433354d19"],["js/vendor.js","d0d6ed1c0632124351f39073feb9cbf0"],["statics/icons/apple-icon-152x152.png","da2b422e2895b9b9c1782a71b6be9d63"],["statics/icons/favicon-16x16.png","efb00e57304380d857603760600da5d5"],["statics/icons/favicon-32x32.png","2f9d7587924933c1912c342b190b53ca"],["statics/icons/icon-192x192.png","8c4120b4e88276badbc808e518572fad"],["statics/icons/icon-512x512.png","a13b2bd5261e2df374128df1aab93001"],["statics/icons/ms-icon-144x144.png","ed12d10fd0407eea42ccaf7af7991146"],["statics/manifest.json","ae10664f4d3a921479e6d4868ae0cdf5"],["statics/quasar-logo.png","3020c8ac2c2872dec7741e5948520093"]],cacheName="sw-precache-v3-my-quasar-app-"+(self.registration?self.registration.scope:""),ignoreUrlParametersMatching=[/^utm_/],addDirectoryIndex=function(e,n){var t=new URL(e);return"/"===t.pathname.slice(-1)&&(t.pathname+=n),t.toString()},cleanResponse=function(e){return e.redirected?("body"in e?Promise.resolve(e.body):e.blob()).then(function(n){return new Response(n,{headers:e.headers,status:e.status,statusText:e.statusText})}):Promise.resolve(e)},createCacheKey=function(e,n,t,a){var c=new URL(e);return a&&c.pathname.match(a)||(c.search+=(c.search?"&":"")+encodeURIComponent(n)+"="+encodeURIComponent(t)),c.toString()},isPathWhitelisted=function(e,n){if(0===e.length)return!0;var t=new URL(n).pathname;return e.some(function(e){return t.match(e)})},stripIgnoredUrlParameters=function(e,n){var t=new URL(e);return t.hash="",t.search=t.search.slice(1).split("&").map(function(e){return e.split("=")}).filter(function(e){return n.every(function(n){return!n.test(e[0])})}).map(function(e){return e.join("=")}).join("&"),t.toString()},hashParamName="_sw-precache",urlsToCacheKeys=new Map(precacheConfig.map(function(e){var n=e[0],t=e[1],a=new URL(n,self.location),c=createCacheKey(a,hashParamName,t,!1);return[a.toString(),c]}));self.addEventListener("install",function(e){e.waitUntil(caches.open(cacheName).then(function(e){return setOfCachedUrls(e).then(function(n){return Promise.all(Array.from(urlsToCacheKeys.values()).map(function(t){if(!n.has(t)){var a=new Request(t,{credentials:"same-origin"});return fetch(a).then(function(n){if(!n.ok)throw new Error("Request for "+t+" returned a response with status "+n.status);return cleanResponse(n).then(function(n){return e.put(t,n)})})}}))})}).then(function(){return self.skipWaiting()}))}),self.addEventListener("activate",function(e){var n=new Set(urlsToCacheKeys.values());e.waitUntil(caches.open(cacheName).then(function(e){return e.keys().then(function(t){return Promise.all(t.map(function(t){if(!n.has(t.url))return e.delete(t)}))})}).then(function(){return self.clients.claim()}))}),self.addEventListener("fetch",function(e){if("GET"===e.request.method){var n,t=stripIgnoredUrlParameters(e.request.url,ignoreUrlParametersMatching);(n=urlsToCacheKeys.has(t))||(t=addDirectoryIndex(t,"index.html"),n=urlsToCacheKeys.has(t));n&&e.respondWith(caches.open(cacheName).then(function(e){return e.match(urlsToCacheKeys.get(t)).then(function(e){if(e)return e;throw Error("The cached response that was expected is missing.")})}).catch(function(n){return console.warn('Couldn\'t serve response for "%s" from cache: %O',e.request.url,n),fetch(e.request)}))}});
|
||||||
|
|
@ -23,11 +23,4 @@ Authorization: {{jwtUser}}
|
||||||
###
|
###
|
||||||
DELETE {{host}}/api/account/token/1
|
DELETE {{host}}/api/account/token/1
|
||||||
Authorization: {{jwtUser}}
|
Authorization: {{jwtUser}}
|
||||||
###
|
|
||||||
PUT {{host}}/api/account/profile
|
|
||||||
Authorization: {{jwtUser}}
|
|
||||||
|
|
||||||
{
|
|
||||||
"id": 3,
|
|
||||||
"theme": "dark"
|
|
||||||
}
|
|
||||||
|
|
@ -6,10 +6,5 @@ PUT {{host}}/api/profile
|
||||||
Authorization: {{jwtUser}}
|
Authorization: {{jwtUser}}
|
||||||
|
|
||||||
{
|
{
|
||||||
"email": "invalid",
|
"theme": "dark"
|
||||||
"name": "test"
|
|
||||||
}
|
}
|
||||||
###
|
|
||||||
DELETE {{host}}/api/profile
|
|
||||||
Authorization: {{jwtUser}}
|
|
||||||
###
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue