adding endpoint to push contact notifications

This commit is contained in:
Roland Osborne 2022-11-13 22:18:54 -08:00
parent 887fd65c75
commit 44801ae6c3
13 changed files with 125 additions and 67 deletions

View File

@ -1,9 +1,7 @@
import { checkResponse, fetchWithTimeout } from './fetchUtil'; import { checkResponse, fetchWithTimeout } from './fetchUtil';
export async function setAccountAccess(server, token, notifications) { export async function setAccountAccess(server, token, appName, appVersion, platofrm, notifications) {
let app = { Name: "indicom", Description: "decentralized communication" } let access = await fetchWithTimeout(`https://${server}/account/access?token=${token}&appName=${appName}&appVersion=${appVersion}&platform=${platform}&deviceToken=${deviceToken}`, { method: 'PUT', body: JSON.stringify(notifications) })
let types = encodeURIComponent(JSON.stringify(notifications));
let access = await fetchWithTimeout(`https://${server}/account/access?token=${token}&appName=${appName}&appVersion=${appVersion}&platform=${platform}&deviceToken=${deviceToken}&notifications=${types}`, { method: 'PUT', body: JSON.stringify(app) })
checkResponse(access) checkResponse(access)
return await access.json() return await access.json()
} }

View File

@ -4,9 +4,7 @@ import base64 from 'react-native-base64'
export async function setLogin(username, server, password, appName, appVersion, platform, deviceToken, notifications) { export async function setLogin(username, server, password, appName, appVersion, platform, deviceToken, notifications) {
let headers = new Headers() let headers = new Headers()
headers.append('Authorization', 'Basic ' + base64.encode(username + ":" + password)); headers.append('Authorization', 'Basic ' + base64.encode(username + ":" + password));
let types = encodeURIComponent(JSON.stringify(notifications)); let login = await fetchWithTimeout(`https://${server}/account/apps?appName=${appName}&appVersion=${appVersion}&platform=${platform}&deviceToken=${deviceToken}`, { method: 'POST', body: JSON.stringify(notifications), headers: headers })
let app = { Name: "topics", Description: "decentralized communication" }
let login = await fetchWithTimeout(`https://${server}/account/apps?appName=${appName}&appVersion=${appVersion}&platform=${platform}&deviceToken=${deviceToken}&notifications=${types}`, { method: 'POST', body: JSON.stringify(app), headers: headers })
checkResponse(login) checkResponse(login)
return await login.json() return await login.json()
} }

View File

@ -71,23 +71,29 @@ export function useAppContext() {
clearWebsocket(); clearWebsocket();
} }
const notifications = [
{ event: 'contact.statusChange', messageTitle: 'Contact Update' },
{ event: 'channel.addChannel.superbasic', messageTitle: 'New Topic' },
{ event: 'contact.addChannelTopic.superbasictopic', messageTitle: 'New Topic Message' },
];
const actions = { const actions = {
available: getAvailable, available: getAvailable,
username: getUsername, username: getUsername,
create: async (server, username, password, token) => { create: async (server, username, password, token) => {
await addAccount(server, username, password, token); await addAccount(server, username, password, token);
const access = await setLogin(username, server, password, getApplicatioName(), getVersion(), getDeviceId(), state.deviceToken, ['contact', 'channel']) const access = await setLogin(username, server, password, getApplicatioName(), getVersion(), getDeviceId(), state.deviceToken, notifications)
await store.actions.setSession({ ...access, server}); await store.actions.setSession({ ...access, server});
await setSession({ ...access, server }); await setSession({ ...access, server });
}, },
access: async (server, token) => { access: async (server, token) => {
const access = await setAccountAccess(server, token, getApplicationName(), getVersion(), getDeviceId(), state.deviceToken, ['contact', 'channel']); const access = await setAccountAccess(server, token, getApplicationName(), getVersion(), getDeviceId(), state.deviceToken, notifications);
await store.actions.setSession({ ...access, server}); await store.actions.setSession({ ...access, server});
await setSession({ ...access, server }); await setSession({ ...access, server });
}, },
login: async (username, password) => { login: async (username, password) => {
const acc = username.split('@'); const acc = username.split('@');
const access = await setLogin(acc[0], acc[1], password, getApplicationName(), getVersion(), getDeviceId(), state.deviceToken, ['contact', 'channel']) const access = await setLogin(acc[0], acc[1], password, getApplicationName(), getVersion(), getDeviceId(), state.deviceToken, notifications)
if (access.pushSupported) { if (access.pushSupported) {
messaging().requestPermission().then(status => {}) messaging().requestPermission().then(status => {})
} }

View File

@ -2059,6 +2059,34 @@ paths:
type: integer type: integer
format: int64 format: int64
/contact/notification:
post:
tags:
- contact
description: Inform contact of a push notification event
operationId: set-push-event
paramters:
- name: contact
in: query
description: contact token
required: true
schema:
type: string
responses:
'200':
description: event set
'401':
description: not authorized
'410':
description: account disabled
'500':
description: internal server error
requestBody:
content:
application/json:
schema:
type: string
/attribute/articles: /attribute/articles:
get: get:
tags: tags:

View File

@ -3,11 +3,9 @@ package databag
import ( import (
"databag/internal/store" "databag/internal/store"
"encoding/hex" "encoding/hex"
"encoding/json"
"github.com/theckman/go-securerandom" "github.com/theckman/go-securerandom"
"gorm.io/gorm" "gorm.io/gorm"
"net/http" "net/http"
"errors"
) )
//AddAccountApp with access token, attach an app to an account generating agent token //AddAccountApp with access token, attach an app to an account generating agent token
@ -24,17 +22,10 @@ func AddAccountApp(w http.ResponseWriter, r *http.Request) {
appVersion := r.FormValue("appVersion") appVersion := r.FormValue("appVersion")
platform := r.FormValue("platform") platform := r.FormValue("platform")
deviceToken := r.FormValue("deviceToken") deviceToken := r.FormValue("deviceToken")
var notifications []string
if r.FormValue("notifications") != "" {
if err := json.Unmarshal([]byte(r.FormValue("notifications")), &notifications); err != nil {
ErrResponse(w, http.StatusBadRequest, errors.New("invalid notification types"));
return;
}
}
// parse app data // parse requested notifications
var appData AppData var notifications []Notification
if err := ParseRequest(r, w, &appData); err != nil { if err := ParseRequest(r, w, &notifications); err != nil {
ErrResponse(w, http.StatusBadRequest, err) ErrResponse(w, http.StatusBadRequest, err)
return return
} }
@ -70,10 +61,12 @@ func AddAccountApp(w http.ResponseWriter, r *http.Request) {
login.Created = session.Created login.Created = session.Created
for _, notification := range notifications { for _, notification := range notifications {
eventType := &store.EventType{} pushEvent := &store.PushEvent{}
eventType.SessionID = session.ID pushEvent.SessionID = session.ID
eventType.Name = notification pushEvent.Event = notification.Event
if res := tx.Save(eventType).Error; res != nil { pushEvent.MessageTitle = notification.MessageTitle
pushEvent.MessageBody = notification.MessageBody
if res := tx.Save(pushEvent).Error; res != nil {
return res return res
} }
} }

View File

@ -3,7 +3,6 @@ package databag
import ( import (
"databag/internal/store" "databag/internal/store"
"encoding/hex" "encoding/hex"
"encoding/json"
"errors" "errors"
"time" "time"
"github.com/theckman/go-securerandom" "github.com/theckman/go-securerandom"
@ -31,17 +30,10 @@ func SetAccountAccess(w http.ResponseWriter, r *http.Request) {
appVersion := r.FormValue("appVersion") appVersion := r.FormValue("appVersion")
platform := r.FormValue("platform") platform := r.FormValue("platform")
deviceToken := r.FormValue("deviceToken") deviceToken := r.FormValue("deviceToken")
var notifications []string
if r.FormValue("notifications") != "" {
if err := json.Unmarshal([]byte(r.FormValue("notifications")), &notifications); err != nil {
ErrResponse(w, http.StatusBadRequest, errors.New("invalid notification types"));
return;
}
}
// parse app data // parse requested notifications
var appData AppData var notifications []Notification
if err := ParseRequest(r, w, &appData); err != nil { if err := ParseRequest(r, w, &notifications); err != nil {
ErrResponse(w, http.StatusBadRequest, err) ErrResponse(w, http.StatusBadRequest, err)
return return
} }
@ -70,10 +62,12 @@ func SetAccountAccess(w http.ResponseWriter, r *http.Request) {
return res return res
} }
for _, notification := range notifications { for _, notification := range notifications {
eventType := &store.EventType{} pushEvent := &store.PushEvent{}
eventType.SessionID = session.ID pushEvent.SessionID = session.ID
eventType.Name = notification pushEvent.Event = notification.Event
if res := tx.Save(eventType).Error; res != nil { pushEvent.MessageTitle = notification.MessageTitle
pushEvent.MessageBody = notification.MessageBody
if res := tx.Save(pushEvent).Error; res != nil {
return res return res
} }
} }

View File

@ -0,0 +1,42 @@
package databag
import (
"databag/internal/store"
"net/http"
)
type push struct {
PushToken string
MessageTitle string
MessageBody string
}
//AddPushEvent notify account of event to push notify
func SetPushEvent(w http.ResponseWriter, r *http.Request) {
card, code, err := ParamContactToken(r, false)
if err != nil {
ErrResponse(w, code, err)
return
}
var event string
if err := ParseRequest(r, w, &event); err != nil {
ErrResponse(w, http.StatusBadRequest, err)
return
}
messages := []push{}
if err := store.DB.Model(&store.Session{}).Select("sessions.push_token, push_events.message_title, push_events.message_body").Joins("left join push_events on push_events.session_id = session.id").Where("sessions.account_id = ? AND session.push_enabled = ?", card.Account.ID, true).Scan(messages).Error; err != nil {
ErrResponse(w, http.StatusInternalServerError, err)
return
}
// send push notification for each
for _, message := range messages {
PrintMsg(message);
}
WriteResponse(w, nil)
}

View File

@ -39,17 +39,13 @@ type Announce struct {
AppToken string `json:"appToken"` AppToken string `json:"appToken"`
} }
//AppData describes app connected to account //Notification describes type of notifications to receive
type AppData struct { type Notification struct {
Name string `json:"name,omitempty"` Event string `json:"event,omitempty"`
Description string `json:"description,omitempty"` MessageTitle string `json:"messageTitle,omitempty"`
URL string `json:"url,omitempty"` MessageBody string `json:"messageBoday,omitempty"`
Image string `json:"image,omitempty"`
Attached int64 `json:"attached"`
} }
//Article slot for account data shared by group list //Article slot for account data shared by group list

View File

@ -524,6 +524,13 @@ var endpoints = routes{
SetViewRevision, SetViewRevision,
}, },
route{
"SetPushEvent",
strings.ToUpper("Post"),
"/contact/notification",
SetPushEvent,
},
route{ route{
"AddChannel", "AddChannel",
strings.ToUpper("Post"), strings.ToUpper("Post"),

View File

@ -7,7 +7,7 @@ func AutoMigrate(db *gorm.DB) {
db.AutoMigrate(&Config{}); db.AutoMigrate(&Config{});
db.AutoMigrate(&App{}); db.AutoMigrate(&App{});
db.AutoMigrate(&Session{}); db.AutoMigrate(&Session{});
db.AutoMigrate(&EventType{}); db.AutoMigrate(&PushEvent{});
db.AutoMigrate(&Account{}); db.AutoMigrate(&Account{});
db.AutoMigrate(&AccountToken{}); db.AutoMigrate(&AccountToken{});
db.AutoMigrate(&GroupSlot{}); db.AutoMigrate(&GroupSlot{});
@ -108,13 +108,15 @@ type Session struct {
Created int64 `gorm:"autoCreateTime"` Created int64 `gorm:"autoCreateTime"`
Account Account `gorm:"references:GUID"` Account Account `gorm:"references:GUID"`
Token string `gorm:"not null;index:sessguid,unique"` Token string `gorm:"not null;index:sessguid,unique"`
EventTypes []EventType PushEvents []PushEvent
} }
type EventType struct { type PushEvent struct {
ID uint `gorm:"primaryKey;not null;unique;autoIncrement"` ID uint `gorm:"primaryKey;not null;unique;autoIncrement"`
SessionID uint `gorm:"not null;index:sessiontype"` SessionID uint `gorm:"not null;index:sessiontype"`
Name string Event string
MessageTitle string
MessageBody string
Session *Session Session *Session
} }

View File

@ -614,11 +614,6 @@ func addTestAccount(username string) (guid string, token string, err error) {
var w *httptest.ResponseRecorder var w *httptest.ResponseRecorder
var access LoginAccess var access LoginAccess
app := AppData{
Name: "Appy",
Description: "A test app",
URL: "http://app.coredb.org",
}
var claim Claim var claim Claim
var msg DataMessage var msg DataMessage
var profile Profile var profile Profile
@ -646,7 +641,8 @@ func addTestAccount(username string) (guid string, token string, err error) {
guid = profile.GUID guid = profile.GUID
// acquire new token for attaching app // acquire new token for attaching app
if r, w, err = NewRequest("POST", "/account/apps", &app); err != nil { notifications := []Notification{}
if r, w, err = NewRequest("POST", "/account/apps", &notifications); err != nil {
return return
} }
SetBasicAuth(r, login) SetBasicAuth(r, login)

View File

@ -1,8 +1,7 @@
import { checkResponse, fetchWithTimeout } from './fetchUtil'; import { checkResponse, fetchWithTimeout } from './fetchUtil';
export async function setAccountAccess(token, appName, appVersion, platform) { export async function setAccountAccess(token, appName, appVersion, platform) {
let app = { Name: "indicom", Description: "decentralized communication" } let access = await fetchWithTimeout(`/account/access?token=${token}&appName=${appName}&appVersion=${appVersion}&platform=${platform}`, { method: 'PUT', body: JSON.stringify([]) })
let access = await fetchWithTimeout(`/account/access?token=${token}&appName=${appName}&appVersion=${appVersion}&platform=${platform}`, { method: 'PUT', body: JSON.stringify(app) })
checkResponse(access) checkResponse(access)
return await access.json() return await access.json()
} }

View File

@ -5,8 +5,7 @@ export async function setLogin(username, password, appName, appVersion, userAgen
const platform = encodeURIComponent(userAgent); const platform = encodeURIComponent(userAgent);
let headers = new Headers() let headers = new Headers()
headers.append('Authorization', 'Basic ' + base64.encode(username + ":" + password)); headers.append('Authorization', 'Basic ' + base64.encode(username + ":" + password));
let app = { Name: "indicom", Description: "decentralized communication" } let login = await fetchWithTimeout(`/account/apps?appName=${appName}&appVersion=${appVersion}&platform=${platform}`, { method: 'POST', body: JSON.stringify([]), headers: headers })
let login = await fetchWithTimeout(`/account/apps?appName=${appName}&appVersion=${appVersion}&platform=${platform}`, { method: 'POST', body: JSON.stringify(app), headers: headers })
checkResponse(login) checkResponse(login)
return await login.json() return await login.json()
} }