Documentation
¶
Overview ¶
Package common holds structures and data which are common across all databases and architectures (JS / Server). This exists because it is often helpful to translate information from several sources into one intermediate form and then translate it back out again.
Note: pointerConvert is needed so we know if a field is the zero value (like "") or missing (like nil). This is the same strategy used by some google data transport libraries written in Go, and also used by Stripe to know if a field is supposed to be the zero value or nil.
Index ¶
- Constants
- Variables
- func ABToAInterface(A []bool) []interface{}
- func ABytesToAInterface(A [][]byte) []interface{}
- func AFToAInterface(A []float64) []interface{}
- func AIToAInterface(A []int64) []interface{}
- func ASToAInterface(AS []string) []interface{}
- func AddFieldPrefix(industryID string, domainID string, schemaID string, k string) string
- func BlobURL(firestoreID string, field string) string
- func Bool(v bool) *bool
- func BytesToAInterface(A []byte) []interface{}
- func CSSEscape(id string) string
- func CloseLogging()
- func ConvertDataToMatchSchema(data *Data, schema *Schema) error
- func CreateRef(IndustryID string, DomainID string, TaskID string, UXID string, ...) string
- func CreateURL(IndustryID string, DomainID string, TaskID string, UXID string, ...) string
- func CreateURLFromRequest(request POSTRequest) string
- func DataIntoStructure(data *Data, ptrToStructure interface{}) error
- func DataSatisfiesSchema(d *Data, s *Schema) error
- func DataToPOSTData(data *Data, request POSTRequest) (map[string]map[string]interface{}, error)
- func Dereference(simple map[string]interface{})
- func FixPOSTRequest(r *POSTRequest) error
- func Float32(v float32) *float32
- func Float64(v float64) *float64
- func GetCloudProvider() string
- func GetCryptographicallyRandString(size int) (string, error)
- func GetDataRef(request POSTRequest) string
- func GetDeploymentID() string
- func GetElasticsearchClientAddresses() []string
- func GetElasticsearchClientPassword() string
- func GetElasticsearchClientUsername() string
- func GetGoogleApplicationCredentials() string
- func GetGoogleProjectID() string
- func GetHubURL() string
- func GetLastBlobBucket() string
- func GetLogger(serviceName string, serviceVersion string) (io.Writer, error)
- func GetPublicPath() string
- func GetRandString(n int) string
- func Int(v int) *int
- func Int32(v int32) *int32
- func Int64(v int64) *int64
- func IsTimeField(key string) bool
- func LogError(errComingIn error)
- func RemoveDataKeyUnderscore(k string) string
- func RemoveExtraFields(data *Data, schema *Schema) error
- func RemoveFieldPrefix(k string) string
- func RemoveNonAlphaNumeric(s string) string
- func ReplaceIndustryDomainSchemaInKey(key string, newIndustry, newDomain, newSchema string) string
- func RoleHasAccess(role *Role, industryID string, domainID string, schemaID string, ...) (bool, error)
- func RoleHasAccessKeyValues(role *Role, industryID string, domainID string, schemaID string, key string, ...) (bool, error)
- func SchemaSatisfiesTask(s *Schema, t *Task) error
- func SchemaSatisfiesUX(s *Schema, ux *UX) error
- func SplitField(field string) (industry, domain, schema, key string)
- func String(v string) *string
- func StructureIntoData(industry string, domain string, schema string, ptrToStructure interface{}, ...) error
- func TaskGoalEvaluate(key string, task *Task, data *Data) (errorMessage string, err error)
- func Uint32(v uint32) *uint32
- func Uint64(v uint64) *uint64
- func ValidateCollection(c string) (err error)
- func ValidateRef(ref string) error
- type Access
- type Action
- type Bot
- type BrowserAction
- type CSS
- type Data
- func (d *Data) CollectionName() string
- func (d *Data) GetABool(suffix string) []bool
- func (d *Data) GetABytes(suffix string) [][]byte
- func (d *Data) GetAFloat(suffix string) []float64
- func (d *Data) GetAInt(suffix string) []int64
- func (d *Data) GetARef(suffix string) []string
- func (d *Data) GetAString(suffix string) []string
- func (d *Data) GetBool(suffix string) *bool
- func (d *Data) GetBytes(suffix string) []byte
- func (d *Data) GetFirestoreID() string
- func (d *Data) GetFloat(suffix string) *float64
- func (d *Data) GetInt(suffix string) *int64
- func (d *Data) GetRef(suffix string) *string
- func (d *Data) GetString(suffix string) *string
- func (d *Data) Init(simple map[string]interface{}) error
- func (d *Data) Merge(toMerge *Data) error
- func (d *Data) Simplify() (map[string]interface{}, error)
- func (d *Data) Validate() error
- type DataTableRequest
- type DataTableResponse
- type FieldSecurityOptions
- type FullTextSearchRequest
- type FullTextSearchResponse
- type FullTextSearchResponseResults
- type GETRequest
- type GETResponse
- type Iter
- type ModDOM
- type POSTRequest
- type POSTResponse
- type PublicMap
- type PublicSiteTemplate
- type Query
- type Queryable
- type Role
- type Schema
- type SelectSearchRequest
- type SelectSearchResponse
- type Task
- func (t *Task) CollectionName() string
- func (t *Task) GetFirestoreID() string
- func (t *Task) Init(simple map[string]interface{}) error
- func (t *Task) Simplify() (map[string]interface{}, error)
- func (t *Task) TaskGoalAdd(associatedField string, name string, helpText string, op1Variable string, ...) error
- func (t *Task) Validate() error
- type UX
- type User
- type WantDocuments
Constants ¶
const ( // CollectionData holds all customer-owned data CollectionData = "data" // CollectionSchema holds all data defining CollectionData's schema CollectionSchema = "schema" // CollectionUser holds all data for particular users CollectionUser = "user" // CollectionRole holds document with authorization information CollectionRole = "role" // CollectionUX holds data which helps define a piece of UI and how users interact with it CollectionUX = "ux" // CollectionTask holds all data which helps bind together Schemed Data for a User in a UX to accomplish some goals CollectionTask = "task" // CollectionBot is where Bot definitions are stored. CollectionBot = "bot" // CollectionAction is where Action definitions are stored. CollectionAction = "action" // CollectionPublicMap contains information which helps route and respond to incoming requests from other domains. CollectionPublicMap = "publicmap" // CollectionCSS contains information related to CSS on websites hosted by Polyapp. CollectionCSS = "css" )
const ( // PolyappIndustryID is a field which holds the Industry PolyappIndustryID = "polyappIndustryID" // PolyappDomainID is a field which holds the Domain PolyappDomainID = "polyappDomainID" // PolyappSchemaID is a field which holds the this grouping of information under the Domain; aka a Schema. PolyappSchemaID = "polyappSchemaID" // PolyappDeprecated is a field which holds whether or not this Document is Deprecated PolyappDeprecated = "polyappDeprecated" // PolyappFirestoreID is a field in non-Firestore databases which holds the FirestoreID. PolyappFirestoreID = "polyappFirestoreID" )
const ( TemplateUserDataID = "EtCKtxdfmz8UmmiGjgaO" TemplateUserUserID = "p3gP9Lrox8pBxqQdeFUH" HomeTaskID = "NrCEAuHUenfkPKXrwafnbwPKx" HomeUXID = "GfzLPQfRAFMPjKgiRCQmMoCDK" HomeSchemaID = "BJVHCgzBvaahJFBMOGTZSniwK" HomeDataID = "lBDjYHsEaKDJAbuWSotncPIPb" )
Variables ¶
var (
BrowserActionOpenNewTab = "Open New Tab"
)
var (
ErrTaskGoalEvaluateNotHardCoded = errors.New("Task Goal Evaluate Not Hard Coded")
)
var IterDone = errors.New("no more items in iterator")
IterDone is returned by an iterator's Next method when the iteration is complete; when there are no more items to return.
Functions ¶
func ABToAInterface ¶
func ABToAInterface(A []bool) []interface{}
func ABytesToAInterface ¶
func ABytesToAInterface(A [][]byte) []interface{}
func AFToAInterface ¶
func AFToAInterface(A []float64) []interface{}
func AIToAInterface ¶
func AIToAInterface(A []int64) []interface{}
func ASToAInterface ¶
func ASToAInterface(AS []string) []interface{}
func AddFieldPrefix ¶
AddFieldPrefix converts a key of the format: "key" to the format: "industry_context_schema_key".
func BlobURL ¶
BlobURL returns the URL of a blob asset like an image or audio file given that asset's ID in Firestore. An example ID would be: industry_domain_schema_field%20name
Note: this is coupled to BlobHandler in defaultservice/main.go
func Bool ¶
Bool is a helper routine that allocates a new bool value to store v and returns a pointer to it.
func BytesToAInterface ¶
func BytesToAInterface(A []byte) []interface{}
func CSSEscape ¶
CSSEscape takes a sequence of characters which could form a valid HTML5 ID and translates them to a sequence of characters which forms a valid HTML4 ID. It does this primarily by escaping characters like leading numbers and !"@#(*)$%, etc.
Reference documentation: https://mathiasbynens.be/notes/css-escapes
Please remember that this does NOT convert invalid characters like ' ' into something like %20. So typically you would call url.PathEscape(id) and then CSSEscape(id).
func CloseLogging ¶
func CloseLogging()
CloseLogging closes the logging connections and flushes all of the logs out.
func ConvertDataToMatchSchema ¶
ConvertDataToMatchSchema finds keys which should be Ints which are currently floats and converts them and finds key which should be Floats which are currently Ints and converts them.
To determine the proper data type, schema is examined.
This should really be called whenever you are retrieving Data from the database but under some circumstances you don't have access to the Schema for a Data so you won't be able to call this. When this is called, you should also call RemoveExtraFields.
func CreateRef ¶
func CreateRef(IndustryID string, DomainID string, TaskID string, UXID string, SchemaID string, DataID string) string
CreateRef is an alias for CreateURL. It forms a URL which is valid as a Ref in common.Data documents.
An example output is: /t/asdlkjad/adslkj/BCiXCONsZuDxjTYEwNOonlLZc?ux=BCiXCONsZuDxjTYEwNOonlLZc&schema=BCiXCONsZuDxjTYEwNOonlLZc&data=BCiXCONsZuDxjTYEwNOonlLZc&user=&role=
func CreateURL ¶
func CreateURL(IndustryID string, DomainID string, TaskID string, UXID string, SchemaID string, DataID string, UserID string, RoleID string, OverrideIndustryID string, OverrideDomainID string, additionalQueryString ...string) string
CreateURL returns a formed URL based on the information provided. polyappNone is converted to "" before use.
An example output is: /t/asdlkjad/adslkj/BCiXCONsZuDxjTYEwNOonlLZc?ux=BCiXCONsZuDxjTYEwNOonlLZc&schema=BCiXCONsZuDxjTYEwNOonlLZc&data=BCiXCONsZuDxjTYEwNOonlLZc&user=&role=
additionalQueryString lets you add arbitrary strings to the end of the URL.
func CreateURLFromRequest ¶
func CreateURLFromRequest(request POSTRequest) string
CreateURLFromRequest translates a POSTRequest into a string URL.
func DataIntoStructure ¶
DataIntoStructure tries to find data elements which have attributes matching tags in the provided structure.
Relevant tags should be formatted like this: `suffix:"Name"`
If no tag is provided, it is assumed the field suffix the exact value so there is no accounting for spaces.
String types will turn data.S and data.Ref into string; and data.AS and data.ARef into []string. Therefore if you have an embedded structure, like a Subtask, you must use the raw ref to allDB.ReadData and do something with it outside this function. This exclusion improves this function's performance and simplifies its purpose.
Special cases: any field with tag PolyappFirestoreID gets data.FirestoreID set into its value. Similar cases: PolyappSchemaID, PolyappDomain, PolyappIndustry
func DataSatisfiesSchema ¶
DataSatisfiesSchema if and only if Data's fields are a subset of or == the Schema's fields.
func DataToPOSTData ¶
func DataToPOSTData(data *Data, request POSTRequest) (map[string]map[string]interface{}, error)
DataToPOSTData converts a *common.Data into the map[string]map[string]interface{} Data which is used in POSTRequest as field "Data" and in POSTResponse as field "DataUpdates".
TODO this function only works on Head Data. Make it work on child Data (subtask Data) too.
func Dereference ¶
func Dereference(simple map[string]interface{})
Dereference dereferences pointer values. For instance, it will turn *string values into string.
func FixPOSTRequest ¶
func FixPOSTRequest(r *POSTRequest) error
FixPOSTRequest modifies a passed in POSTRequest. It does NOT handle retrieving the auth header.
Call this to deal with special characters in the URL and trailing slashes and such.
func Float32 ¶
Float32 is a helper routine that allocates a new float32 value to store v and returns a pointer to it.
func Float64 ¶
Float64 is a helper routine that allocates a new float64 value to store v and returns a pointer to it.
func GetCloudProvider ¶
func GetCloudProvider() string
GetCloudProvider returns "" for no cloud or "GOOGLE" for Google Cloud.
func GetCryptographicallyRandString ¶
GetCryptographicallyRandString always returns a cryptographically random string of length >= size.
For a faster version which guarantees the string length, use GetRandString(n int).
func GetDataRef ¶
func GetDataRef(request POSTRequest) string
GetDataRef is the first key in AllData. This func should stay in sync with getDataRef on the client.
func GetDeploymentID ¶
func GetDeploymentID() string
GetDeploymentID return "LocalDeployment" for no cloud or the ID of the deployment.
func GetElasticsearchClientAddresses ¶
func GetElasticsearchClientAddresses() []string
GetElasticsearchClientAddresses returns an HTTPS endpoint for an Elasticsearch client.
func GetElasticsearchClientPassword ¶
func GetElasticsearchClientPassword() string
GetElasticsearchClientPassword returns the Elasticsearch Client Password.
func GetElasticsearchClientUsername ¶
func GetElasticsearchClientUsername() string
GetElasticsearchClientUsername returns the Elasticsearch Client Username.
func GetGoogleApplicationCredentials ¶
func GetGoogleApplicationCredentials() string
GetGoogleApplicationCredentials returns the GOOGLE_APPLICATION_CREDENTIALS variable.
This exists to confine os.Getenv calls to this file.
func GetGoogleProjectID ¶
func GetGoogleProjectID() string
GetGoogleProjectID returns the GOOGLE_PROJECT_ID environment variable.
This exists to confine os.Getenv calls to this file.
func GetLastBlobBucket ¶
func GetLastBlobBucket() string
GetLastBlobBucket returns the name of the Google Cloud Bucket / S3 container / etc. which was used to store blobs in the last environment. Ex. 1: Dev bucket is returned when in Staging. Ex. 2: Staging bucket is returned in Prod.
This is used during environment installation. Blobs in the last environment may be copied over into the new environment.
func GetLogger ¶
GetLogger populates the logging clients and contexts. It also gives you a Writer you can use for error logging.
After calling this, you MUST call 'defer CloseLogging()'
func GetPublicPath ¶
func GetPublicPath() string
GetPublicPath returns the path to the 'public' directory in this git repo.
func GetRandString ¶
GetRandString returns a random string of length n with an intermediate level of entropy. https://stackoverflow.com/questions/22892120/how-to-generate-a-random-string-of-a-fixed-length-in-go#31832326
func Int ¶
Int is a helper routine that allocates a new int32 value to store v and returns a pointer to it, but unlike Int32 its argument value is an int.
func Int32 ¶
Int32 is a helper routine that allocates a new int32 value to store v and returns a pointer to it.
func Int64 ¶
Int64 is a helper routine that allocates a new int64 value to store v and returns a pointer to it.
func IsTimeField ¶
IsTimeField checks if a field's name is maybe a date or time field stored as a UNIX timestamp.
In addition to calling this function, you should also use this logic on the field value:
_, isTimeField := toSet.(int64)
func RemoveDataKeyUnderscore ¶
RemoveDataKeyUnderscore converts a key of the format: "_industry_context_schema_key" to the format: "industry_context_schema_key".
func RemoveExtraFields ¶
RemoveExtraFields from Data. "Extra Fields" are fields which are present in Data but not present in the Schema of this Data. Extra fields may be introduced when a field is removed from a Task.
This function should always be called after func ConvertDataToMatchSchema or else some data which could have been rectified may be deleted.
func RemoveFieldPrefix ¶
RemoveFieldPrefix converts a key of the format: "industry_context_schema_key" to the format: "key".
func RemoveNonAlphaNumeric ¶
RemoveNonAlphaNumeric removes non-alphanumeric characters from the string passed in it leaves in spaces in the middle but removes them at the edges with strings.TrimSpace
func RoleHasAccess ¶
func RoleHasAccess(role *Role, industryID string, domainID string, schemaID string, accessType byte) (bool, error)
RoleHasAccess returns true if the role has access to both the industry and domain.
accessType must be one of: 'c', 'r', 'u', 'd'
func RoleHasAccessKeyValues ¶
func RoleHasAccessKeyValues(role *Role, industryID string, domainID string, schemaID string, key string, value string) (bool, error)
RoleHasAccessKeyValues checks if a role has the requested cast-insensitive value at the given case-sensitive key for an Access which includes the Industry and Domain and (optionally) Schema. Returns true, nil if access is allowed.
func SchemaSatisfiesTask ¶
SchemaSatisfiesTask ensures all of a Task's inputs are available from a particular Schema.
func SchemaSatisfiesUX ¶
SchemaSatisfiesUX ensures a Schema and UX are compatible We *could* go through every HTML ID in UX.HTML and ensure it has something in Schema & pull additional Schemas recursively. But we do not because that would be a lot of work to verify that the "SchemaID" variables are not lying.
func SplitField ¶
func String ¶
String is a helper routine that allocates a new string value to store v and returns a pointer to it.
func StructureIntoData ¶
func StructureIntoData(industry string, domain string, schema string, ptrToStructure interface{}, data *Data) error
StructureIntoData is the reverse of DataIntoStructure: it takes data in a structure and places it into *common.Data. Fields in Data need to be prefixed with industry_domain_schema_ so those arguments to this function are required.
structure must be a pointer to a structure where we can get the data to retrieve.
data must have already called Init().
func TaskGoalEvaluate ¶
TaskGoalEvaluate returns errorMessage "" if the TaskGoal passes validation, an errorMessage string, or an error in failures.
func Uint32 ¶
Uint32 is a helper routine that allocates a new uint32 value to store v and returns a pointer to it.
func Uint64 ¶
Uint64 is a helper routine that allocates a new uint64 value to store v and returns a pointer to it.
func ValidateCollection ¶
ValidateCollection validates that the collection string passed in is one of the known collections
func ValidateRef ¶
ValidateRef ensures something which ought to be a Ref type follows the format of a Ref type.
Types ¶
type Access ¶
type Access struct { // Industry is the Industry the Datas being granted access to are in. Industry string // Domain is the Domain of the Datas being granted access to. Domain string // Schema (optional) of the Datas being granted access to. // If Schema is not set or is empty then this Access grants access to all Schemas in the Industry/Domain combination. Schema string // Create access allows a user to "Create" a new Data, usually with the "Create Data" button. Create bool // Read access allows a user to perform GET requests with the Data, but never POST or similar requests. Read bool // Update access allows a user to edit an existing Data. Update bool // Delete access allows a user to delete a Data. Delete bool // KeyValue grants custom access control attributes. For example, "EditTask": true grants access to using the Edit // Task Bot. KeyValue map[string]string `suffix:"Key Value"` }
Access defines what Industry, Domain, and (optionally) Schema it grants access to and which privileges are granted.
type Action ¶
type Action struct { FirestoreID string `json:"polyappFirestoreID"` // Name describes this Action Name string // HelpText explains why this action exists and what it does. HelpText string Deprecated *bool `json:"polyappDeprecated"` }
Action is a name of a function or a chromedp.Action call. Actions are executed with RunBot(bot, data)
Functions are of the format: somefuncname()
chromedp.Action calls are of the format: chromedp.Action
TODO implement the logic needed to get chromedp.Action calls to work. TODO every action a human can take should be doable by a chromedp.Action call, so why not have each action taken translated first into a chromedp.Action and stored in a big list of actions. Periodically updates are transmitted, and then that chromedp.Action list is replayed to apply the changes to the system before it's committed. If things were done this way it might be easier to sync the idbCRUD and firestoreCRUD databases. Doing things this way would also make regression testing really easy. Just replay the chromedp.Actions using a Bot & verify the Data at the end is the same.
func (*Action) CollectionName ¶
CollectionName is the literal name of this collection. This is used by generic functions.
func (*Action) GetFirestoreID ¶
GetFirestoreID returns the FirestoreID property.
type Bot ¶
type Bot struct { FirestoreID string `json:"polyappFirestoreID"` Name string HelpText string `suffix:"Help Text"` // Actions are of type Action. This array contains an ordered list of IDs of Actions to execute. ActionIDs []string `suffix:"Action IDs"` Deprecated *bool `json:"polyappDeprecated"` }
Bot is a software bot. It is an ordered list of Actions.
func (*Bot) CollectionName ¶
CollectionName is the literal name of this collection. This is used by generic functions.
func (*Bot) GetFirestoreID ¶
GetFirestoreID returns the FirestoreID element.
type BrowserAction ¶
type BrowserAction struct { Name string // Name of the action to initiate. One of: BrowserActionOpenNewTab, ... Data string // Data which modifies how the browser action works. At some point this should be a map[string]interface{} instead. }
BrowserAction initiates some Javascript which performs things which aren't doable with ModDOMs, like opening a new browser tab.
func (BrowserAction) Validate ¶
func (b BrowserAction) Validate() error
Validate ensures the values in BrowserAction are valid
type CSS ¶
type CSS struct { FirestoreID string `json:"polyappFirestoreID"` // Tags are search terms used to identify CSS. It could be the name of the CSS, describe what it looks like, or categorize it somehow. // The first Tag is always the "Name" of the CSS. Tags []string // CompiledCSS is the output from the compilation process. It is served directly to end users. CompiledCSS *string Deprecated *bool `json:"polyappDeprecated"` }
CSS contains CSS which is unique to certain pages or websites. This is intended to be used to 'theme' public websites.
func (*CSS) CollectionName ¶
CollectionName is the literal name of this collection. This is used by generic functions.
func (*CSS) GetFirestoreID ¶
GetFirestoreID returns the FirestoreID property.
type Data ¶
type Data struct { FirestoreID string `json:"polyappFirestoreID"` IndustryID string `json:"polyappIndustryID" firestore:"polyappIndustryID"` DomainID string `json:"polyappDomainID" firestore:"polyappDomainID"` SchemaID string `json:"polyappSchemaID" firestore:"polyappSchemaID"` Deprecated *bool `json:"polyappDeprecated" firestore:"polyappDeprecated"` // SchemaCache is the Schema of this Data. The Schema can't change after the Data has been read, so // it should be safe to cache it. Schema is extremely useful for BackPopulate and similar functions. SchemaCache Schema `json:"-"` // Ref is used for complicated data structures where you need objects within objects. Its format is that of a link: // // /[industry]/[domain]/[task]?ux=[UXID]&schema=[SchemaID]&data=[dataID] // // You can create links with common.CreateRef(). // // There are two ways to display a Ref to a user. One is to display the link within an <a> element. // The other renders the content of the task as an embedded Task. The decision on which to do is taken by the UX object. // See the UX struct for more documentation on this issue. // // Note: although Refs are stored with an _ prefix in Schema, inside Data they are stored without the _ prefix. Ref map[string]*string // S is string data S map[string]*string // I is int data. Uses 64 bits even though JS only does some operations on 32-bit integers I map[string]*int64 // B is boolean data. B map[string]*bool // F is floating point numbers (number in JS) F map[string]*float64 // ARef is array of Ref. See Ref's description for help. ARef map[string][]string // AS is array of strings AS map[string][]string // AI is array of ints AI map[string][]int64 // AB is array of bools AB map[string][]bool // AF is array of floats AF map[string][]float64 // Bytes is an array of bytes. It is stored into an object whose name is: SchemaName_FirestoreID_Key Bytes map[string][]byte // ABytes is an array of blobs. It is stored into an object whose name is: SchemaName_FirestoreID_Key_index. ABytes map[string][][]byte // Deprecated. To delete a field, set its value to nil. Nils map[string]bool }
Data holds the values people enter when filling out forms. It can be difficult to interact with directly because you need to know, for a given key, what data type it is. This 'data type definition' is provided by type Schema. I have previously tried to leave this data structure inside a more generic map, but I found that to be even more difficult to use.
IndustryID, DomainID and SchemaID provide context. For right now, SchemaID is often set to the ID of the schema.
func CreateDataFromSchema ¶
CreateDataFromSchema is very helpful if you are trying to load a new page with a new Data. It is used when you take an action in the UI which creates a new Data document which users then immediately navigate to.
overrideData does NOT copy the override's Industry, Domain or Schema IDs. It only copies over the actual data and only if that data's Field is present in the Schema which is also being passed in.
Side effects: This function creates the Data in the DB.
func SchemaConvert ¶
SchemaConvert translates a Data document which satisfies oldSchema into a Data document which satisfies NewSchema and returns the converted Data document *without a FirestoreID*. The original Data document is untouched.
There are 3 possibilities for Fields in the Data document. (1) The field is present in the new schema. In this case the field is copied into the new schema. (2) The field is not present in the new schema at the correct DataType. In this case the "convertKey" map is checked. If the field is present as a key & the value of the key is present at convertKey[field] & the the type of the old and new keys match then the field is added to the new Data. (3) The field is invalid or can't be converted. In this case the field is not included in the new Data.
func (*Data) CollectionName ¶
CollectionName is the literal name of this collection. This is used by generic functions.
func (*Data) GetAString ¶
GetAString returns nil if the key is nil; a valid []string otherwise
func (*Data) GetFirestoreID ¶
GetFirestoreID returns this firestore ID.
func (*Data) Init ¶
Init makes all of the maps and initializes them. If the inputs are non-nil, it populates DataTypes from the map[string]interface{} structure. If the input key exists and its value is nil the key is stored in Nils.
Strings are assumed to be References if their keys are prefixed with "_".
Keys are assumed to be PathEscaped, so for instance "%20" is unescaped to " ". The opposite of this operation is performed when the UX is created with encodings in its IDs - aka the opposite should already exist in the database.
func (*Data) Merge ¶
Merge merges a Data 'toMerge' into the pointer receiver. It requires that they have the same FirestoreID.
Merging basically creates a superset of the inputs. If you want to remove a value then set its key into the Nils in toMerge. When this function finds keys in the Nils category it searches the d *Data & replaces its value appropriately. Conversely if a value is set in the Nils in d *Data but has a real value in toMerge *Data, the Nils entry is removed. By removing the Nils entry we ensure the new value from toMerge overwrites the null value in d *Data.
type DataTableRequest ¶
type DataTableRequest struct { // IndustryID of the request. IndustryID string `json:"industry"` // DomainID of the request. DomainID string `json:"domain"` // SchemaID of the request. SchemaID string `json:"schema"` // Draw counter. This is used by DataTables to ensure that the Ajax returns from server-side processing requests are // drawn in sequence by DataTables (Ajax requests are asynchronous and thus can return out of sequence). // This is used as part of the draw return parameter (see below). Draw int `json:"draw"` // Paging first record indicator. This is the start point in the current data set (0 index based - i.e. 0 is the first record). Start int `json:"start"` // Number of records that the table can display in the current draw. It is expected that the number of records // returned will be equal to this number, unless the server has fewer records to return. Note that this can be -1 to // indicate that all records should be returned (although that negates any benefits of server-side processing!). Length int `json:"length"` // format: order[i][column] where i is the 0-start index of the column. // Column to which ordering should be applied for the i-th column. This is an index reference to the columns array of information that is also submitted to the server. OrderColumn map[int]int // format: order[i][dir] where i is the 0-start index of the column. // Ordering direction for the i-th column. It will be asc or desc to indicate ascending ordering or descending ordering, respectively. OrderDir map[int]string // format: columns[i][name] where i is the 0-start index of the column. // Column's name, as defined by columns.name. ColumnsName []string // format: columns[i][orderable] where i is the 0-start index of the column. // Flag to indicate if this column is orderable (true) or not (false). This is controlled by columns.orderable. ColumnsOrderable []bool // LastDocumentID is a set of custom query parameters created to hold the last row of data currently visible on screen. // This is supposed to be used by Firestore to enable pagination. LastDocumentID string // RequiredColumns is an array of IDs of columns whose values must be present for a row to be visible. RequiredColumns []string // SearchInput is the input to the search box. Searching is handled as part of the AllDBQuery when you do a GET // request for DataTables. See that function for more information. // // TODO support regex, smart, and caseInsensitive options not being false (right now all must be false). SearchInput string // InitialSearch (optional) if set when the page loads this value becomes the initial value sent up in the GET // request for SearchInput. InitialSearch string // InitialOrderColumn (optional) if set when the page loads this value becomes the initial value sent up in the GET // request for OrderColumn (sort of - this sets the column # being sorted). InitialOrderColumn string // InitialLastDocumentID (optional) if set when the page loads this value becomes the initial value sent up in the GET // request for LastDocumentID. InitialLastDocumentID string }
DataTableRequest is based on https://datatables.net/manual/server-side.
Features turned on/off can be found when DataTables is initialized: $(headElement).find('.polyappDataTable').DataTable
Features which are on and we need handling for on the server: lengthChange, ordering, paging, serverSide.
func CreateDataTableRequest ¶
func CreateDataTableRequest(URL url.URL) (DataTableRequest, error)
CreateDataTableRequest from a /polyappDataTable request URL.
type DataTableResponse ¶
type DataTableResponse struct { // The draw counter that this object is a response to - from the draw parameter sent as part of the data request. // Note that it is strongly recommended for security reasons that you cast this parameter to an integer, rather than // simply echoing back to the client what it sent in the draw parameter, in order to prevent Cross Site Scripting // (XSS) attacks. Draw int `json:"draw"` // Total records, before filtering (i.e. the total number of records in the database) RecordsTotal int `json:"recordsTotal"` // Total records, after filtering (i.e. the total number of records after filtering has been applied - not just the // number of records being returned for this page of data). RecordsFiltered int `json:"recordsFiltered"` // The data to be displayed in the table. This is an array of data source objects, one for each row, which will be // used by DataTables. Note that this parameter's name can be changed using the ajax option's dataSrc property. Data [][]string `json:"data"` // Optional: If an error occurs during the running of the server-side processing script, you can inform the user of // this error by passing back the error message to be displayed using this parameter. Do not include if there is // no error. Error string `json:"error"` // LastDocumentID is the last returned DocumentID LastDocumentID string `json:"lastDocumentID"` }
DataTableResponse is based on https://datatables.net/manual/server-side
type FieldSecurityOptions ¶
type FieldSecurityOptions struct {
Readonly bool
}
FieldSecurityOptions holds access control information about a particular field like: industry_domain_schema_field name
type FullTextSearchRequest ¶
func CreateFullTextSearchRequest ¶
func CreateFullTextSearchRequest(URL *url.URL) (FullTextSearchRequest, error)
CreateFullTextSearchRequest from a /polyappFullTextSearch request.
type FullTextSearchResponse ¶
type FullTextSearchResponse struct { Results []FullTextSearchResponseResults ResultHTML string // ResultHTML is HTML which can be used to display search results in lieu of parsing the results yourself. }
type FullTextSearchResponseResults ¶
type FullTextSearchResponseResults struct { Name string // Name or Title of the result HelpText string // HelpText of the result is only available when searching collection "task". ChangeDataURL string // URL of the result's Change Data page NewDataURL string // URL of the result's New Data page EditTaskURL string // URL of the result's Edit Task page }
type GETRequest ¶
type GETRequest struct { // IndustryID is part of the context of this request. IndustryID string `json:"IndustryID"` // OverrideIndustryID is used if the URL includes 'industry' parameter. OverrideIndustryID string `json:"OverrideIndustryID"` // DomainID is part of the context of this request. DomainID string `json:"DomainID"` // OverrideDomainID is used if the URL includes 'domain' parameter. OverrideDomainID string `json:"OverrideDomainID"` // TaskID of the Task in the database is used to tie the User, Data, Schema, and UX together into a single package TaskID string `json:"TaskID"` // OverrideTaskID is used if the URL includes 'task' parameter. OverrideTaskID string `json:"OverrideTaskID"` // UXID is the ID of the UI data in the database. UXID string `json:"UXID"` // SchemaID is the ID of the Data's schema in the database. SchemaID string `json:"SchemaID"` // DataID of the data instance in the database. DataID string `json:"DataID"` // UserID of the user making the change. All access checks and the like are performed with this user. // Do not confuse the UserID with the UID. The UID is from Firebase; the UserID from Polyapp's Firestore DB. // You could have a UID of xyz and a UserID of hyk if the User were to be a Bot authorized under a human's uid. UserID string `json:"UserID"` // UserCache is a cache of the User when the request began and it was authenticated. // This may not change if the User is updated during the request. UserCache *User // RoleID is the role for a particular user. RoleID string `json:"RoleID"` // ModifyID is the ID of an object in the DB you wish to modify. This is used exclusively on the server // and is used in tasks which are modifying objects like type UX or type Schema or if you want to refresh a report. ModifyID string `json:"ModifyID"` // AltShell if true uses lightshell.index instead of index.html to wrap the response from ux.HTML. AltShell string `json:"AltShell"` // FinishURL is where this page navigates to after this Task is done. Since the FinishURL could contain a FinishURL, // there could be a chain of pages you'll be going back to after visiting this one. // // Should be encoded with url.PathEscape prior to being used in a URL. Should be decoded with url.PathUnescape prior // to being stored into the FinishURL variable. FinishURL string // PublicPath is used for public / semipublic pages to identify the path. This is used to avoid overloading TaskID. PublicPath string `json:"PublicPath"` }
GETRequest is an incoming GET request. If you make changes here you may also need to make changes in type 'POSTRequest'.
func CreateGETRequest ¶
func CreateGETRequest(URL url.URL) (GETRequest, error)
CreateGETRequest returns a GETRequest and an error if it fails. It does NOT handle retrieving the auth header. FYI this is substantially similar to public/main.js function createPOSTBody.
func ParseRef ¶
func ParseRef(ref string) (GETRequest, error)
ParseRef is the opposite of CreateRef. It parses a string Ref into a GETRequest data structure.
func (GETRequest) GetDomain ¶
func (request GETRequest) GetDomain() string
GetDomain considers any overrides to the domain.
func (GETRequest) GetIndustry ¶
func (request GETRequest) GetIndustry() string
GetIndustry considers any overrides to the industry.
func (GETRequest) GetTask ¶
func (request GETRequest) GetTask() string
GetTask considers any overrides to the task.
func (GETRequest) Validate ¶
func (request GETRequest) Validate() error
Validate ensures the structure of GETRequest is valid
type GETResponse ¶
type GETResponse struct { // All of the HTML in the page you're responding with. HTML string // RedirectURL, if set, returns an HTTP redirect to the client. RedirectURL string }
GETResponse can be used to create a reply to an incoming GET request.
func (GETResponse) Validate ¶
func (response GETResponse) Validate() error
Validate ensures the structure of GETResponse is valid
type Iter ¶
type Iter interface { Next() (Queryable, error) Stop() // Length is number of available results. Length() int }
Iter lets you iterate over results from a query. It is created with a function like 'CreateDBIterator'.
The Iter interface design is based on Firestore's iterator interface design.
type ModDOM ¶
type ModDOM struct { // DeleteSelector is all of the elements you're trying to remove DeleteSelector string // InsertSelector is the ID of the element we're inserting near InsertSelector string // Action is the position parameter in 'insertAdjacentHTML'. Options: beforebegin afterbegin beforeend afterend // Action also accepts "wrap" which calls jQuery's wrap() function. Action string // HTML is what we are putting in to the DOM. It's the text parameter in 'insertAdjacentHTML' HTML string // AddClassSelector is optional and can select more than one element. If populated, AddClasses should be populated. AddClassSelector string // AddClasses is optional. It's a list of CSS classes to add to the elements found by AddClassSelector. AddClasses []string // RemoveClassSelector is optional and can select more than one element. If populated, RemoveClasses should be populated. RemoveClassSelector string // RemoveClasses is optional. It's a list of CSS classes to remove from the elements found by RemoveClassSelector. RemoveClasses []string }
ModDOM contains everything the client needs to modify the DOM with 'insertAdjacentHTML' function call.
type POSTRequest ¶
type POSTRequest struct { // MessageID identifies this message. This ensures 1 message gets 1 response. MessageID string `json:"MessageID"` // IndustryID is part of the context of this request. IndustryID string `json:"IndustryID"` // OverrideIndustryID is used if the URL includes 'industry' parameter. OverrideIndustryID string `json:"OverrideIndustryID"` // DomainID is part of the context of this request. DomainID string `json:"DomainID"` // OverrideDomainID is used if the URL includes 'domain' parameter. OverrideDomainID string `json:"OverrideDomainID"` // TaskID of the Task in the database is used to tie the User, Data, Schema, and UX together into a single package TaskID string `json:"TaskID"` // TaskCache is a cache of the Task when it was last read. This is not necessarily updated if the Task document is updated // during the request. TaskCache *Task // OverrideTaskID is used if the URL includes 'task' parameter. OverrideTaskID string `json:"OverrideTaskID"` // Data is the marshalled information from the Task. Data is in a map of Document ID -> Data in that Document. // Within Data in that Document, there is a map from ElementID -> data like booleans, strings, numbers, etc. // // You can create this data structure with func DataToPOSTData Data map[string]map[string]interface{} `json:"Data"` // UXID is the ID of the UI data in the database. UXID string `json:"UXID"` // UXCache is a cache of the UX when it was last read. This is not necessarily updated if the UX document is updated // during the request. UXCache *UX // SchemaID is the ID of the Data's schema in the database. SchemaID string `json:"SchemaID"` // SchemaCache is a cache of the Schema when it was last read. This is not necessarily updated if the Schema document is updated // during the request. SchemaCache *Schema // DataID of the data instance in the database. DataID string `json:"DataID"` // UserID of the user making the change. All access checks and the like are performed with this user. UserID string `json:"UserID"` // UserCache is a cache of the User when it was last read. This not necessarily updated if the User document is updated // during the request. UserCache *User // PublicMapOwningUserID is the ID of the User which owns (created) this URL. PublicMapOwningUser User // RoleID for a Role. This is NOT required - usually the User document's Role is considered instead. RoleID string `json:"RoleID"` // ModifyID for an object which is not ModifyID string `json:"ModifyID"` // PublicPath is used for public / semipublic pages to identify the path. This is used to avoid overloading TaskID. PublicPath string `json:"PublicPath"` // RecaptchaResponse is the response from the Recaptcha API or an empty string. RecaptchaResponse string `json:"RecaptchaResponse"` // FinishURL is where this page navigates to after this Task is done. Since the FinishURL could contain a FinishURL, // there could be a chain of pages you'll be going back to after visiting this one. FinishURL string // IsDone is set programatically and if true indicates that Data contained the Done boolean. IsDone bool // WantDocuments are arrays of FirestoreIDs of documents the client wants. WantDocuments WantDocuments `json:"WantDocuments"` }
POSTRequest contains all information sent from the client. If you're making changes here you may also need to make changes in type 'GETRequest'.
NOTE: If you modify this structure, you MUST consider the security implications for public access. See PublicMapSitePOST().
func (POSTRequest) GetDomain ¶
func (p POSTRequest) GetDomain() string
GetDomain considers any overrides to the domain.
func (POSTRequest) GetIndustry ¶
func (p POSTRequest) GetIndustry() string
GetIndustry considers any overrides to the industry.
func (POSTRequest) GetTask ¶
func (p POSTRequest) GetTask() string
GetTask considers any overrides to the task.
func (*POSTRequest) Validate ¶
func (p *POSTRequest) Validate() error
Validate ensures the structure of POSTRequest is valid
type POSTResponse ¶
type POSTResponse struct { // MessageID is a randomly generated string. It's identical to MessageID on the incoming message. MessageID string // NewURL is optional. Set this to set the address bar. NewURL string // BrowserActions is optional. Setting this initiates some Javascript which performs things which aren't doable with ModDOMs, // like opening a new browser tab. BrowserActions []BrowserAction // DataUpdates is a subset of the marshalled information from the Task. Data is in a map of Document ID -> Data in that Document. // Within Data in that Document, there is a map from ElementID -> data like booleans, strings, numbers, etc. // // You can create this data structure with func DataToPOSTData DataUpdates map[string]map[string]interface{} // DataDocuments can be cached on the client in their local database. DataDocuments []*Data // RoleDocuments can be cached on the client in their local database. RoleDocuments []*Role // SchemaDocuments can be cached on the client in their local database. SchemaDocuments []*Schema // TaskDocuments can be cached on the client in their local database. TaskDocuments []*Task // UserDocuments can be cached on the client in their local database. UserDocuments []*User // UXDocuments can be cached on the client in their local database. UXDocuments []*UX // ModDOMs are things we're putting in to the DOM. ModDOMs []ModDOM }
POSTResponse applies some changes to the DOM (ModDOMs) in order.
func (*POSTResponse) Init ¶
func (r *POSTResponse) Init(request POSTRequest)
Init initializes the common.POSTResponse structure and removes any of its current contents.
func (POSTResponse) Validate ¶
func (r POSTResponse) Validate() error
Validate ensures the structure of POSTResponse is valid
type PublicMap ¶
type PublicMap struct { FirestoreID string `json:"polyappFirestoreID"` // HostAndPath includes subdomains, like: "example.com" or "a.example.com", and probably looks like this: "example.com/pay/" // typical construction looks like: c.Request().Host + "/" + c.Request().URL.EscapedPath() // // The HostAndPath ALWAYS ends in a / HostAndPath string // IndustryID is the Industry associated with this HostAndPath. IndustryID string // DomainID is the domain associated with this HostAndPath. DomainID string // UXID is the UX associated with this HostAndPath, if any. UXID *string // TaskID is the Task associated with this HostAndPath, if any. TaskID *string // SchemaID is the Schema associated with this HostAndPath, if any. SchemaID *string // OwningUserID is a FirestoreID for whatever user owns this PublicMap. This is set when the PublicMap is created // and is used to verify that this page is being paid for (aka the subscription is still active). OwningUserID string Deprecated *bool `json:"polyappDeprecated"` }
PublicMap is used as a lookup mechanism when trying to find the content of a web page. For instance, if you wanted to find the content of "example.com/pay" you would first query for that URL in the HostAndPath parameter. You would then take the first (and only) result and examine its UXID, TaskID, and other data and use that to construct a request in the form of private requests. You can then use that private request to access the rest of the code normally.
func (*PublicMap) CollectionName ¶
CollectionName is the literal name of this collection. This is used by generic functions.
func (*PublicMap) GetFirestoreID ¶
GetFirestoreID returns the FirestoreID property.
type PublicSiteTemplate ¶
type PublicSiteTemplate struct { IsPublic bool AllContent string TopBar string LeftBar string RightBar string BottomBar string Title string MetaDescription string MetaAuthor string MetaKeywords string HeadTag string // same as HeadTag in UX. IconPath string CSSPath string FullAuthPage bool // True and this will be treated as a page requiring full Auth. }
PublicSiteTemplate includes the inputs to the template at genPublic/index.html
type Query ¶
type Query interface { // Init the query. This should be called immediately after creating the Query object. Init(industryID string, domainID string, schemaID string, firestoreCollection string) // AddEquals ensures the key k's value == v, a string AddEquals(k string, v string) // AddArrayContains ensures the key k's value, which should be an array, contains the value v. AddArrayContains(k string, v string) error // QueryRead uses the query to perform a read via an Iterator interface. QueryRead() (Iter, error) }
Query in a database-agnostic way. You must Init the Query, optionally add query constraints like "AddEquals", and then call QueryRead(). QueryRead() returns an iterator interface which can be used to iterate over the query results.
The Query interface design is based on Firestore's query interface design.
type Queryable ¶
type Queryable interface { Validate() error Simplify() (map[string]interface{}, error) GetFirestoreID() string // Init should populate the structure with the contents of 'simple'. It assumes there are no existing contents. // // Init implementations MUST set Queryable.FirestoreID = simple[polyappFirestoreID]. Init(simple map[string]interface{}) error // CollectionName is something like common.CollectionData or "schema". This helps with the creation of generic methods. CollectionName() string }
Queryable implementation is a prerequisite for using the Query interface because Query needs to use Iter which returns a Queryable.
type Role ¶
type Role struct { FirestoreID string `json:"polyappFirestoreID" suffix:"Role ID"` Name string // Name of this role. Used when searching for roles. // Access defines to what a Role grants access. // // key: industry_domain // value: one or more of the letters 'c' 'r' 'u' 'd' // // "domain" could contain an underscore. But since no Industry contains an underscore we know the first underscore must be the delimiter. Access []Access `json:"Access" suffix:"Access"` Deprecated *bool `json:"polyappDeprecated" firestore:"polyappDeprecated"` }
Role is a Role-collection object pointed to by a User. Its arrays can be nil; that just means they weren't set in the request.
Note: Access is stored as a map in the database. Firestore supports []map[string]interface{}
func (*Role) CollectionName ¶
CollectionName is the literal name of this collection. This is used by generic functions.
func (*Role) GetFirestoreID ¶
GetFirestoreID returns this firestore ID.
type Schema ¶
type Schema struct { FirestoreID string `json:"polyappFirestoreID"` // For this document NextSchemaID *string // linked list pointing to the next schema version's ID in the database. Name *string // Used when searching the collection. Typically identical to Task's Name. IndustryID string `json:"polyappIndustryID" firestore:"polyappIndustryID"` // FirestoreID DomainID string `json:"polyappDomainID" firestore:"polyappDomainID"` // FirestoreID SchemaID string `json:"polyappSchemaID" firestore:"polyappSchemaID"` // FirestoreID // Field Name -> Type. "Ref" "S" "I" "B" "F" are the non-array options. There's also "ARef", "AS", "AI", "AB", "AF". There's also "Bytes" for Bytes. DataTypes map[string]string DataHelpText map[string]string // Field Name -> Help Text. DataKeys []string // List of Keys (Field Names) which are used in DataTypes. Used to find duplicate keys. // IsPublic is true if this is publicly accessible. It is false or not set otherwise. IsPublic bool Deprecated *bool `json:"polyappDeprecated" firestore:"polyappDeprecated"` }
Schema of some Data. Schema must play well with both the corresponding Data and the UX and Task.
func SchemaConvertSchema ¶
SchemaConvertSchema converts a Schema into a new Schema. For example, convert schema with ID "A" to one with ID "B".
The new Schema is returned.
func (*Schema) CollectionName ¶
CollectionName is the literal name of this collection. This is used by generic functions.
func (*Schema) GetFirestoreID ¶
GetFirestoreID returns this firestore ID.
func (*Schema) Merge ¶
Merge merges a Schema 'toMerge' into the pointer receiver. It requires that they have the same FirestoreID.
type SelectSearchRequest ¶
func CreateSelectSearchRequest ¶
func CreateSelectSearchRequest(URL *url.URL) (SelectSearchRequest, error)
CreateSelectSearchRequest from a /polyappSearch request.
type SelectSearchResponse ¶
type SelectSearchResponse struct {
ResultHTML string
}
type Task ¶
type Task struct { FirestoreID string `json:"polyappFirestoreID"` IndustryID string `json:"polyappIndustryID"` DomainID string `json:"polyappDomainID"` // Name associated with the Task. Name string // HelpText associated with the Task. HelpText string // TaskGoals should always be created programmatically with TaskGoalAdd() // // TaskGoals should always be evaluated with TaskGoalEvaluate() // // TaskGoals are stored internally in a JSON format derived from the 'taskGoal' struct with keys which are either // prefixed with 'polyappError' which means they're field-specific or which are NOT prefixed & therefore task-level. TaskGoals map[string]string // FieldSecurity holds access control properties which are related to the ability to access a field. FieldSecurity map[string]*FieldSecurityOptions // BotsTriggeredAtLoad are IDs of Bots which are triggered on every GET request for this task. // When creating one of these Bots, keep in mind that the user will be waiting at a loading screen while this is happening. BotsTriggeredAtLoad []string // BotsTriggeredContinuously are IDs of Bots which are triggered on every POST request. // Since POST requests are triggered automatically and periodically as part of auto-save these Bots run frequently. // // These Bots run before BotsTriggeredAtDone. BotsTriggeredContinuously []string // BotsTriggeredAtDone are IDs of Bots which are triggered when the "Done" value is set to True. BotsTriggeredAtDone []string // BotStaticData is provided to bots when they are run. This data is supposed to be read-only and encapsulates // information which changes on a Task by Task basis but not a Data by Data basis. For example there is an Action // which can open a new Data for a Task when a user clicks "Done". This Action allows you to configure which Data to // open next by inputting a Query into the Task's BotStaticData. The Action knows which current Data // you are on, so it can run the Query with StartAfter set to the current data, thereby returning the next result // in the Query. // // Keys are the last chunk of fields after the last "_" (aka the field's Name). Values are arbitrary and might be parsed to ints or floats. BotStaticData map[string]string // IsPublic is true if this is publicly accessible. It is false or not set otherwise. // // IsPublic may eventually be deprecated when we figure out a more granular access control method. IsPublic bool Deprecated *bool `json:"polyappDeprecated" firestore:"polyappDeprecated"` }
Task stores validation requirements, a list of bots, and bot configuration data. Its Name is shown at the top of the form which you see when loading the Task.
When someone thinks of Polyapp they will probably think of Tasks as a collection of things they see, the database schema, and the validation for the Task. In reality the Task struct and document in the database has no reference to the schema or the user interface or the data.
The Task is not directly coupled to Data, Schema, or UX. Instead it can merely be 'satisfied' by the Data. This setup means one Task could be used with multiple Schema, UX, or Data.
func (*Task) CollectionName ¶
CollectionName is the literal name of this collection. This is used by generic functions.
func (*Task) GetFirestoreID ¶
GetFirestoreID returns this firestore ID.
func (*Task) TaskGoalAdd ¶
func (t *Task) TaskGoalAdd(associatedField string, name string, helpText string, op1Variable string, operation string, op2Variable string, op2Constant interface{}, errorMessage string) error
TaskGoalAdd adds a Task Goal to the TaskGoals map. Include op2Variable XOR op2Constant.
Inputs:
associatedField: the name of a field an error should be shown underneath. Typically associatedField == op1Variable || associatedField == op2Variable. If associatedField is not set, key = name. If set, key = "polyappError" + name
name: the user-readable (and human-searchable) name of this validator.
helpText: a user-readable description of why this validator exists, etc.
op1Variable: if [op1Variable] [operation] [op2Variable] { return "" } else { return errorMessage }
operation: if [op1Variable] [operation] [op2Variable] { return "" } else { return errorMessage }
op2Variable: if [op1Variable] [operation] [op2Variable] { return "" } else { return errorMessage }
op2Constant: if [op1Variable] [operation] [op2Constant] { return "" } else { return errorMessage }
errorMessage: if [op1Variable] [operation] [op2Variable] { return "" } else { return errorMessage }
type UX ¶
type UX struct { FirestoreID string `json:"polyappFirestoreID"` IndustryID string `json:"polyappIndustryID"` DomainID string `json:"polyappDomainID"` SchemaID string `json:"polyappSchemaID"` // HTML is everything this UX needs to host some Task or Tasks. It does NOT include navigation or metadata. HTML *string Navbar *string // Title is a value in the header of an HTML page: https://www.w3schools.com/tags/tag_title.asp Title *string // MetaDescription is one of the named meta HTML elements: https://www.w3schools.com/tags/tag_meta.asp MetaDescription *string // MetaKeywords is one of the named meta HTML elements: https://www.w3schools.com/tags/tag_meta.asp MetaKeywords *string // MetaAuthor is one of the named meta HTML elements: https://www.w3schools.com/tags/tag_meta.asp MetaAuthor *string // HeadTag contains additional content which is directly placed into the Head tag. This could include scripts. HeadTag *string // IconPath is the path to an icon you can show in the upper right hand corner. IconPath *string // CSSPath is the path you can call to get a custom CSS file. If not set, the CSS which is loaded is Bootstrap's default CSS. // // This may also be known as "ThemePath" from the User. CSSPath *string // SelectFields are Fields / UI IDs in THIS SCHEMA -> search field, aka the Field in the searched schema. // To use this, when the UI is being loaded you must run the query given in the value field. Use the values you // get from that query to populate the Select markup options. // // This could also be implemented via a data-* attribute, but doing so would require trusting the client to decide // what to search. Since searching is inherently more expensive than other operations things have been implemented // this way instead. SelectFields map[string]string // IsPublic is true if this is publicly accessible. It is false or not set otherwise. IsPublic bool // FullAuthPage is True if you want to demand users use full authentication. FullAuthPage *bool Deprecated *bool `json:"polyappDeprecated" firestore:"polyappDeprecated"` }
UX contains both the UI as stored in the HTML field and data which helps render that UI.
This structure is at the bottom of a dependency chain. Task is satisfied by some Schemas; Schema is satisfied by Data which is following that Schema. UX is different in that it can contain nested components which could come from different Data documents which follow different Schemas. So a simple UX with no ARef or Ref is satisfied by a single Schema, but if it contains ARef or Ref keys the schema must contain those too.
func (*UX) CollectionName ¶
CollectionName is the literal name of this collection. This is used by generic functions.
func (*UX) GetFirestoreID ¶
GetFirestoreID returns this firestore ID.
type User ¶
type User struct { FirestoreID string `json:"polyappFirestoreID" suffix:"User ID"` UID *string `suffix:"UID"` FullName *string `suffix:"Full Name"` PhotoURL *string `suffix:"Photo URL"` EmailVerified *bool `suffix:"Email Verified"` PhoneNumber *string `suffix:"Phone Number"` Email *string `suffix:"Email"` // Roles holds Firestore IDs of Role documents Roles []string `suffix:"Roles"` // BotsTriggeredAtLoad are triggered every time this User loads a Task. BotsTriggeredAtLoad []string `suffix:"Bots Triggered At Load"` // BotsTriggeredAtDone are triggered every time this User clicks "Done" on a Task. BotsTriggeredAtDone []string `suffix:"Bots Triggered At Done"` HomeTask string `suffix:"Home Task"` HomeUX string `suffix:"Home UX"` HomeSchema string `suffix:"Home Schema"` HomeData string `suffix:"Home Data"` // ThemePath like /blob/assets/??/polyapp_TaskSchemaUX_KxZRoxrRpyECTbCudVfXKnmHB_Bootstrap%20Theme?cacheBuster=1628015252293 ThemePath *string `suffix:"Theme Path"` Deprecated *bool `json:"polyappDeprecated" firestore:"polyappDeprecated"` }
User is someone using the software. Roles can be nil.
func (*User) CollectionName ¶
CollectionName is the literal name of this collection. This is used by generic functions.
func (*User) GetFirestoreID ¶
GetFirestoreID returns this firestore ID.