2020-05-19 20:46:41 +00:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"encoding/json"
|
|
|
|
"fmt"
|
|
|
|
"git.openprivacy.ca/openprivacy/log"
|
|
|
|
"github.com/therecipe/qt/core"
|
|
|
|
"io/ioutil"
|
|
|
|
"os"
|
|
|
|
"reflect"
|
|
|
|
"regexp"
|
|
|
|
"strings"
|
|
|
|
"time"
|
|
|
|
)
|
|
|
|
|
|
|
|
type FormEntry struct {
|
|
|
|
core.QObject
|
|
|
|
|
|
|
|
API, FormID, FormName, User string
|
|
|
|
FolderName string `json:",omitempty"`
|
|
|
|
Token string `json:",omitempty"`
|
|
|
|
RemotePubKey string `json:",omitempty"`
|
|
|
|
LocalPubKey string `json:",omitempty"`
|
|
|
|
Error string `json:",omitempty"`
|
|
|
|
LastDownload time.Time
|
|
|
|
Submissions int
|
|
|
|
}
|
|
|
|
|
|
|
|
type FormDataModel struct {
|
|
|
|
core.QAbstractTableModel
|
|
|
|
|
|
|
|
_ string `property:"error"`
|
|
|
|
_ string `property:"cwd"`
|
|
|
|
_ map[int]*core.QByteArray `property:"roles"`
|
|
|
|
_ func() `constructor:"init"`
|
|
|
|
|
|
|
|
_ func(*FormEntry) `signal:"addFormEntry,auto"`
|
|
|
|
modelData []FormEntry
|
|
|
|
|
|
|
|
_ func(string) `signal:"createLocalFormEntry,auto"`
|
|
|
|
_ func() `signal:"requestEIR,auto"` // request this.EndInsertRecord() on gui thread
|
|
|
|
}
|
|
|
|
|
|
|
|
func (this *FormDataModel) init() {
|
|
|
|
mdt := reflect.TypeOf(this.modelData).Elem()
|
|
|
|
roles := make(map[int]*core.QByteArray)
|
|
|
|
for i := 0; i < mdt.NumField(); i++ {
|
|
|
|
roles[int(core.Qt__UserRole) + 1 + i] = core.NewQByteArray2(mdt.Field(i).Name, -1)
|
|
|
|
}
|
|
|
|
roles[int(core.Qt__DisplayRole)] = core.NewQByteArray2("display", -1)
|
|
|
|
this.SetRoles(roles)
|
|
|
|
|
|
|
|
this.ConnectData(this.data)
|
|
|
|
this.ConnectRowCount(this.rowCount)
|
|
|
|
this.ConnectColumnCount(this.columnCount)
|
|
|
|
this.ConnectHeaderData(this.headerData)
|
|
|
|
this.ConnectRoleNames(this.roleNames)
|
|
|
|
//this.ConnectAddFormEntry(this.addFormEntry)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (this *FormDataModel) roleNames() map[int]*core.QByteArray {
|
|
|
|
return this.Roles()
|
|
|
|
}
|
|
|
|
|
|
|
|
func (this *FormDataModel) data(index *core.QModelIndex, role int) *core.QVariant {
|
|
|
|
if !index.IsValid() {
|
|
|
|
return core.NewQVariant()
|
|
|
|
}
|
|
|
|
if index.Row() >= len(this.modelData) {
|
|
|
|
return core.NewQVariant()
|
|
|
|
}
|
|
|
|
|
|
|
|
log.Infof("getting role %v column %v", role, index.Column())
|
|
|
|
|
|
|
|
if role == int(core.Qt__DisplayRole) {
|
|
|
|
role = index.Column() + int(core.Qt__UserRole) + 1
|
|
|
|
}
|
|
|
|
|
|
|
|
// modelData-element [role]-field value (aka the data ~_~)
|
|
|
|
mderfv := reflect.ValueOf(this.modelData[index.Row()]).Field(role - int(core.Qt__UserRole) - 1)
|
|
|
|
typeStr := reflect.TypeOf(this.modelData).Elem().Field(role - int(core.Qt__UserRole) - 1).Type.String()
|
|
|
|
if typeStr == "string" {
|
|
|
|
return core.NewQVariant1(mderfv.String())
|
|
|
|
} else if strings.HasPrefix(typeStr, "int") {
|
|
|
|
return core.NewQVariant1(mderfv.Int())
|
|
|
|
} else if strings.HasPrefix(typeStr, "float") {
|
|
|
|
return core.NewQVariant1(mderfv.Float())
|
|
|
|
} else if typeStr == "bool" {
|
|
|
|
return core.NewQVariant1(mderfv.Bool())
|
|
|
|
}
|
|
|
|
|
|
|
|
return core.NewQVariant1("unknown type " + typeStr)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (this *FormDataModel) headerData(section int, orientation core.Qt__Orientation, role int) *core.QVariant {
|
|
|
|
if role != int(core.Qt__DisplayRole) || orientation == core.Qt__Vertical {
|
|
|
|
return this.HeaderDataDefault(section, orientation, role)
|
|
|
|
}
|
|
|
|
|
|
|
|
mdt := reflect.TypeOf(this.modelData).Elem()
|
|
|
|
return core.NewQVariant12(mdt.Field(section).Name)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (this *FormDataModel) rowCount(parent *core.QModelIndex) int {
|
|
|
|
return len(this.modelData)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (this *FormDataModel) columnCount(parent *core.QModelIndex) int {
|
|
|
|
return reflect.TypeOf(this.modelData).Elem().NumField()
|
|
|
|
}
|
|
|
|
|
|
|
|
func (this *FormDataModel) addFormEntry(fe *FormEntry) {
|
|
|
|
this.BeginInsertRows(core.NewQModelIndex(), len(this.modelData), len(this.modelData))
|
|
|
|
this.modelData = append(this.modelData, *fe)
|
|
|
|
this.RequestEIR()
|
|
|
|
}
|
|
|
|
|
|
|
|
func (this *FormDataModel) createLocalFormEntry(name string) {
|
|
|
|
go this.createLocalFormEntry_thread(name)
|
|
|
|
}
|
|
|
|
|
|
|
|
//todo: figure out error handling ie notifying the user throughout
|
|
|
|
func (this *FormDataModel) createLocalFormEntry_thread(name string) {
|
|
|
|
dirname := FormEntryDirectoryName(this.Cwd(), "local", name)
|
|
|
|
fe := &FormEntry{
|
|
|
|
API: "local",
|
|
|
|
FormName: name,
|
|
|
|
User: "n/a",
|
|
|
|
Token: "n/a",
|
|
|
|
}
|
|
|
|
|
|
|
|
// put in file
|
|
|
|
err := os.Mkdir(dirname, 0700)
|
|
|
|
if err != nil {
|
|
|
|
log.Errorf("could't make directory %s: %v", dirname, err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
jsonBytes, err := json.Marshal(fe)
|
|
|
|
if err != nil {
|
|
|
|
log.Errorf("couldn't marshal formentry: %v", err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
err = ioutil.WriteFile(dirname + string(os.PathSeparator) + "config.json", jsonBytes, 0600)
|
|
|
|
if err != nil {
|
|
|
|
log.Errorf("couldn't write config.json")
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
fe.FolderName = dirname
|
|
|
|
this.addFormEntry(fe)
|
|
|
|
}
|
|
|
|
|
|
|
|
// perform this.EndInsertRows() on the gui thread
|
|
|
|
func (this *FormDataModel) requestEIR() {
|
|
|
|
this.EndInsertRows()
|
|
|
|
}
|
|
|
|
|
|
|
|
// creates a folder name using api+formName
|
|
|
|
// as well as _## suffix so that the return
|
|
|
|
// value doesn't exist already in cwd
|
|
|
|
func FormEntryDirectoryName(cwd, api, formName string) string {
|
|
|
|
// take the hostname component of the api
|
|
|
|
reApi := regexp.MustCompile(`^(\w+://)?([^/]+)(/.*)?$`) // -> "$2"
|
|
|
|
// get rid of most characters
|
|
|
|
reName := regexp.MustCompile(`[^a-zA-Z0-9_.]`) // -> ""
|
|
|
|
// base = cwd + reName(reApi(api).formName)
|
|
|
|
basename := cwd + string(os.PathSeparator) + reName.ReplaceAllString(fmt.Sprintf("%s.%s", reApi.ReplaceAllString(api, `$2`), formName), ``)
|
|
|
|
|
|
|
|
// i++ until cwd/base_i does not exist
|
|
|
|
_, e := os.Stat(basename)
|
|
|
|
i := 1
|
|
|
|
for ; os.IsExist(e); i++ { _, e = os.Stat(fmt.Sprintf("%s_%d", basename, i)) }
|
|
|
|
if i > 1 {
|
|
|
|
basename = fmt.Sprintf("%s_%d", basename, i)
|
|
|
|
}
|
|
|
|
|
|
|
|
return basename
|
|
|
|
}
|
|
|
|
|
|
|
|
func BuildFormModel(fdm *FormDataModel, datadir string) {
|
2020-05-19 22:07:25 +00:00
|
|
|
fdm.addFormEntry(LoadFormEntry("wip1"))
|
|
|
|
fdm.addFormEntry(LoadFormEntry("wip2"))
|
|
|
|
fdm.addFormEntry(LoadFormEntry("wip3"))
|
2020-05-19 20:46:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func LoadFormEntry(path string) *FormEntry {
|
2020-05-19 22:07:25 +00:00
|
|
|
fe := &FormEntry{
|
|
|
|
API: "api1",
|
|
|
|
FormID: "fid1",
|
|
|
|
FormName: "fn1",
|
|
|
|
User: "user1",
|
|
|
|
FolderName: "fn1",
|
|
|
|
Token: "token1",
|
|
|
|
RemotePubKey: "pubkey1",
|
|
|
|
LocalPubKey: "localkey2",
|
|
|
|
Error: "error1",
|
|
|
|
LastDownload: time.Now(),
|
|
|
|
Submissions: 123,
|
2020-05-19 20:46:41 +00:00
|
|
|
}
|
|
|
|
return fe
|
|
|
|
}
|
|
|
|
|
|
|
|
func FormEntryError(path, msg string) *FormEntry {
|
|
|
|
return &FormEntry{
|
|
|
|
FolderName: path,
|
|
|
|
Error: msg,
|
|
|
|
}
|
|
|
|
}
|