diff --git a/README.md b/README.md index 61876f67..4a083b4b 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ The mission is to bring software dev inspired features (refactoring, testing, li ## Latest version -v0.42.0 +v0.43.0 ## OS Support diff --git a/app/app/components/global-settings.js b/app/app/components/global-settings.js index 405d4ced..cadea72f 100644 --- a/app/app/components/global-settings.js +++ b/app/app/components/global-settings.js @@ -16,14 +16,14 @@ const { } = Ember; export default Ember.Component.extend({ - SMTPHostEmptyError: computed.empty('model.global.host'), - SMTPPortEmptyError: computed.empty('model.global.port'), - SMTPSenderEmptyError: computed.empty('model.global.sender'), - SMTPUserIdEmptyError: computed.empty('model.global.userid'), - SMTPPasswordEmptyError: computed.empty('model.global.password'), + SMTPHostEmptyError: computed.empty('model.smtp.host'), + SMTPPortEmptyError: computed.empty('model.smtp.port'), + SMTPSenderEmptyError: computed.empty('model.smtp.sender'), + SMTPUserIdEmptyError: computed.empty('model.smtp.userid'), + SMTPPasswordEmptyError: computed.empty('model.smtp.password'), actions: { - save() { + saveSMTP() { if (this.get('SMTPHostEmptyError')) { $("#smtp-host").focus(); return; @@ -45,7 +45,12 @@ export default Ember.Component.extend({ return; } - this.get('save')().then(() => { + this.get('saveSMTP')().then(() => { + }); + }, + + saveLicense() { + this.get('saveLicense')().then(() => { }); } } diff --git a/app/app/components/layout/zone-content.js b/app/app/components/layout/zone-content.js index cb25c125..f8f457d6 100644 --- a/app/app/components/layout/zone-content.js +++ b/app/app/components/layout/zone-content.js @@ -10,6 +10,18 @@ // https://documize.com import Ember from 'ember'; +import NotifierMixin from '../../mixins/notifier'; -export default Ember.Component.extend({ +const { + inject: { service } +} = Ember; + +export default Ember.Component.extend(NotifierMixin, { + appMeta :service(), + + didRender() { + if (this.get('appMeta').invalidLicense()) { + this.showNotification(`!! Expired or invalid license !!`); + } + } }); diff --git a/app/app/pods/customize/global/controller.js b/app/app/pods/customize/global/controller.js index 499377a2..e94bfb61 100644 --- a/app/app/pods/customize/global/controller.js +++ b/app/app/pods/customize/global/controller.js @@ -16,9 +16,17 @@ export default Ember.Controller.extend(NotifierMixin, { global: Ember.inject.service(), actions: { - save() { + saveSMTP() { if(this.get('session.isGlobalAdmin')) { - return this.get('global').saveConfig(this.model.global).then(() => { + return this.get('global').saveSMTPConfig(this.model.smtp).then(() => { + this.showNotification('Saved'); + }); + } + }, + + saveLicense() { + if(this.get('session.isGlobalAdmin')) { + return this.get('global').saveLicense(this.model.license).then(() => { this.showNotification('Saved'); }); } diff --git a/app/app/pods/customize/global/route.js b/app/app/pods/customize/global/route.js index 57701fc0..396dce26 100644 --- a/app/app/pods/customize/global/route.js +++ b/app/app/pods/customize/global/route.js @@ -26,7 +26,8 @@ export default Ember.Route.extend(AuthenticatedRouteMixin, { model() { return RSVP.hash({ - global: this.get('global').getConfig() + smtp: this.get('global').getSMTPConfig(), + license: this.get('global').getLicense() }); }, diff --git a/app/app/pods/customize/global/template.hbs b/app/app/pods/customize/global/template.hbs index bdf3d052..0ea61f38 100644 --- a/app/app/pods/customize/global/template.hbs +++ b/app/app/pods/customize/global/template.hbs @@ -1 +1 @@ -{{global-settings model=model save=(action 'save')}} +{{global-settings model=model saveSMTP=(action 'saveSMTP') saveLicense=(action 'saveLicense')}} diff --git a/app/app/services/app-meta.js b/app/app/services/app-meta.js index 1c8dae9a..1ebf3705 100644 --- a/app/app/services/app-meta.js +++ b/app/app/services/app-meta.js @@ -27,9 +27,15 @@ export default Ember.Service.extend({ title: '', version: '', message: '', + edition: 'Community', + valid: true, allowAnonymousAccess: false, setupMode: false, + invalidLicense() { + return this.valid === false; + }, + getBaseUrl(endpoint) { return [this.get('endpoint'), endpoint].join('/'); }, diff --git a/app/app/services/global.js b/app/app/services/global.js index 2a37875a..64bdb24c 100644 --- a/app/app/services/global.js +++ b/app/app/services/global.js @@ -21,10 +21,10 @@ export default Ember.Service.extend({ appMeta: service(), store: service(), - // Returns global configuration. - getConfig() { + // Returns SMTP configuration. + getSMTPConfig() { if(this.get('sessionService.isGlobalAdmin')) { - return this.get('ajax').request(`global`, { + return this.get('ajax').request(`global/smtp`, { method: 'GET' }).then((response) => { return response; @@ -32,13 +32,36 @@ export default Ember.Service.extend({ } }, - // Saves global configuration. - saveConfig(config) { + // Saves SMTP configuration. + saveSMTPConfig(config) { if(this.get('sessionService.isGlobalAdmin')) { - return this.get('ajax').request(`global`, { + return this.get('ajax').request(`global/smtp`, { method: 'PUT', data: JSON.stringify(config) }); } + }, + + // Returns product license. + getLicense() { + if(this.get('sessionService.isGlobalAdmin')) { + return this.get('ajax').request(`global/license`, { + method: 'GET', + dataType: "text" + }).then((response) => { + return response; + }); + } + }, + + // Saves product license. + saveLicense(license) { + if(this.get('sessionService.isGlobalAdmin')) { + return this.get('ajax').request(`global/license`, { + method: 'PUT', + dataType: 'text', + data: license + }); + } } }); diff --git a/app/app/templates/components/global-settings.hbs b/app/app/templates/components/global-settings.hbs index 06375426..26a42073 100644 --- a/app/app/templates/components/global-settings.hbs +++ b/app/app/templates/components/global-settings.hbs @@ -1,32 +1,48 @@
-
Global Settings
-
Settings applicable for all tenants
+
Mail Server Settings
+
Used for sending email notifications
e.g. my.host.com
- {{focus-input id="smtp-host" type="text" value=model.global.host class=(if SMTPHostEmptyError 'error')}} + {{focus-input id="smtp-host" type="text" value=model.smtp.host class=(if SMTPHostEmptyError 'error')}}
e.g. 587
- {{input id="smtp-port" type="text" value=model.global.port class=(if SMTPPortEmptyError 'error')}} + {{input id="smtp-port" type="text" value=model.smtp.port class=(if SMTPPortEmptyError 'error')}}
e.g. noreply@documize.com
- {{input id="smtp-sender" type="text" value=model.global.sender class=(if SMTPSenderEmptyError 'error')}} + {{input id="smtp-sender" type="text" value=model.smtp.sender class=(if SMTPSenderEmptyError 'error')}}
Your credentials
- {{input id="smtp-userid" type="text" value=model.global.userid class=(if SMTPUserIdEmptyError 'error')}} + {{input id="smtp-userid" type="text" value=model.smtp.userid class=(if SMTPUserIdEmptyError 'error')}}
Your credentials
- {{input id="smtp-password" type="text" value=model.global.password class=(if SMTPPasswordEmptyError 'error')}} + {{input id="smtp-password" type="text" value=model.smtp.password class=(if SMTPPasswordEmptyError 'error')}}
-
save
+
save
+
+ +
+
+ +
+
+
Optional Edition License
+
Only applies to Enterprise Edition
+
+
+ +
XML format accepted
+ {{textarea value=model.license rows="15"}} +
+
save
diff --git a/app/app/utils/net.js b/app/app/utils/net.js index afceec75..8bac8ccf 100644 --- a/app/app/utils/net.js +++ b/app/app/utils/net.js @@ -63,9 +63,22 @@ function isAjaxNotFoundError(reason) { return false; } +function isInvalidLicenseError(reason) { + if (typeof reason === "undefined" || typeof reason.errors === "undefined") { + return false; + } + + if (reason.errors.length > 0 && reason.errors[0].status === "402") { + return true; + } + + return false; +} + export default { getSubdomain, getAppUrl, isAjaxAccessError, isAjaxNotFoundError, + isInvalidLicenseError, }; diff --git a/app/package.json b/app/package.json index 2e0fba82..937279f5 100644 --- a/app/package.json +++ b/app/package.json @@ -1,6 +1,6 @@ { "name": "documize", - "version": "0.42.0", + "version": "0.43.0", "description": "The Document IDE", "private": true, "repository": "", diff --git a/cmd/documize-community/documize.go b/cmd/documize-community/documize.go index 79390d9b..0379f1bc 100644 --- a/cmd/documize-community/documize.go +++ b/cmd/documize-community/documize.go @@ -18,8 +18,7 @@ import ( "github.com/documize/community/core/section" _ "github.com/documize/community/embed" // the compressed front-end code and static data - - _ "github.com/go-sql-driver/mysql" // the mysql driver is required behind the scenes + _ "github.com/go-sql-driver/mysql" // the mysql driver is required behind the scenes ) func main() { diff --git a/core/api/endpoint/global_endpoint.go b/core/api/endpoint/global_endpoint.go index 2f397ba6..79561fc2 100644 --- a/core/api/endpoint/global_endpoint.go +++ b/core/api/endpoint/global_endpoint.go @@ -16,13 +16,15 @@ import ( "io/ioutil" "net/http" + "encoding/xml" + "fmt" "github.com/documize/community/core/api/request" "github.com/documize/community/core/api/util" ) -// GetGlobalConfig returns installation-wide settings -func GetGlobalConfig(w http.ResponseWriter, r *http.Request) { - method := "GetGlobalConfig" +// GetSMTPConfig returns installation-wide SMTP settings +func GetSMTPConfig(w http.ResponseWriter, r *http.Request) { + method := "GetSMTPConfig" p := request.GetPersister(r) if !p.Context.Global { @@ -39,16 +41,16 @@ func GetGlobalConfig(w http.ResponseWriter, r *http.Request) { json, err := json.Marshal(y) if err != nil { - writeJSONMarshalError(w, method, "GetGlobalConfig", err) + writeJSONMarshalError(w, method, "SMTP", err) return } util.WriteSuccessBytes(w, json) } -// SaveGlobalConfig persists global configuration. -func SaveGlobalConfig(w http.ResponseWriter, r *http.Request) { - method := "SaveGlobalConfig" +// SaveSMTPConfig persists global SMTP configuration. +func SaveSMTPConfig(w http.ResponseWriter, r *http.Request) { + method := "SaveSMTPConfig" p := request.GetPersister(r) if !p.Context.Global { @@ -79,3 +81,98 @@ func SaveGlobalConfig(w http.ResponseWriter, r *http.Request) { util.WriteSuccessEmptyJSON(w) } + +// GetLicense returns product license +func GetLicense(w http.ResponseWriter, r *http.Request) { + // method := "GetLicense" + p := request.GetPersister(r) + + if !p.Context.Global { + writeForbiddenError(w) + return + } + + // SMTP settings + config := request.ConfigString("EDITION-LICENSE", "") + if len(config) == 0 { + config = "{}" + } + + x := &licenseXML{Key: "", Signature: ""} + lj := licenseJSON{} + + err := json.Unmarshal([]byte(config), &lj) + if err == nil { + x.Key = lj.Key + x.Signature = lj.Signature + } else { + fmt.Println(err) + } + + output, err := xml.Marshal(x) + if err != nil { + fmt.Printf("error: %v\n", err) + } + + w.WriteHeader(http.StatusOK) + w.Write(output) +} + +// SaveLicense persists product license +func SaveLicense(w http.ResponseWriter, r *http.Request) { + method := "SaveLicense" + p := request.GetPersister(r) + + if !p.Context.Global { + writeForbiddenError(w) + return + } + + defer r.Body.Close() + + body, err := ioutil.ReadAll(r.Body) + if err != nil { + writePayloadError(w, method, err) + return + } + + var config string + config = string(body) + lj := licenseJSON{} + x := licenseXML{Key: "", Signature: ""} + + err = xml.Unmarshal([]byte(config), &x) + if err == nil { + lj.Key = x.Key + lj.Signature = x.Signature + } else { + fmt.Println(err) + } + + j, err := json.Marshal(lj) + js := "{}" + if err == nil { + js = string(j) + } + + request.ConfigSet("EDITION-LICENSE", js) + + util.WriteSuccessEmptyJSON(w) +} + +type licenseXML struct { + XMLName xml.Name `xml:"DocumizeLicense"` + Key string + Signature string +} +type licenseJSON struct { + Key string `json:"key"` + Signature string `json:"signature"` +} + +/* + + some key + some signature + +*/ diff --git a/core/api/endpoint/init.go b/core/api/endpoint/init.go index 9c564ad3..98cf53a0 100644 --- a/core/api/endpoint/init.go +++ b/core/api/endpoint/init.go @@ -41,6 +41,11 @@ func writeTransactionError(w http.ResponseWriter, method string, err error) { log.Error(fmt.Sprintf("Unable to get database transaction for method %s", method), err) } +// IsInvalidLicense returns true if license is invalid +func IsInvalidLicense() bool { + return Product.License.Valid == false +} + /* func WriteAddRecordError(w http.ResponseWriter, method string, err error) { w.Header().Set("Content-Type", "application/json; charset=utf-8") diff --git a/core/api/endpoint/label_endpoint.go b/core/api/endpoint/label_endpoint.go index 4d80962d..18a7cf69 100644 --- a/core/api/endpoint/label_endpoint.go +++ b/core/api/endpoint/label_endpoint.go @@ -32,6 +32,11 @@ import ( // AddFolder creates a new folder. func AddFolder(w http.ResponseWriter, r *http.Request) { + if IsInvalidLicense() { + util.WriteBadLicense(w) + return + } + method := "AddFolder" p := request.GetPersister(r) @@ -263,6 +268,11 @@ func UpdateFolder(w http.ResponseWriter, r *http.Request) { // RemoveFolder moves documents to another folder before deleting it func RemoveFolder(w http.ResponseWriter, r *http.Request) { + if IsInvalidLicense() { + util.WriteBadLicense(w) + return + } + method := "RemoveFolder" p := request.GetPersister(r) diff --git a/core/api/endpoint/meta_endpoint.go b/core/api/endpoint/meta_endpoint.go index 6cec5a05..61b34572 100644 --- a/core/api/endpoint/meta_endpoint.go +++ b/core/api/endpoint/meta_endpoint.go @@ -18,7 +18,6 @@ import ( "net/http" "text/template" - "github.com/documize/community/core" "github.com/documize/community/core/api/entity" "github.com/documize/community/core/api/request" "github.com/documize/community/core/log" @@ -41,13 +40,13 @@ func GetMeta(w http.ResponseWriter, r *http.Request) { return } - product := core.Product() - data.OrgID = org.RefID data.Title = org.Title data.Message = org.Message data.AllowAnonymousAccess = org.AllowAnonymousAccess - data.Version = product.Version + data.Version = Product.Version + data.Edition = Product.License.Edition + data.Valid = Product.License.Valid json, err := json.Marshal(data) diff --git a/core/api/endpoint/page_endpoint.go b/core/api/endpoint/page_endpoint.go index c606c966..27d89bdc 100644 --- a/core/api/endpoint/page_endpoint.go +++ b/core/api/endpoint/page_endpoint.go @@ -33,6 +33,11 @@ import ( // AddDocumentPage inserts new section into document. func AddDocumentPage(w http.ResponseWriter, r *http.Request) { + if IsInvalidLicense() { + util.WriteBadLicense(w) + return + } + method := "AddDocumentPage" p := request.GetPersister(r) @@ -286,6 +291,11 @@ func GetDocumentPagesBatch(w http.ResponseWriter, r *http.Request) { // DeleteDocumentPage deletes a page. func DeleteDocumentPage(w http.ResponseWriter, r *http.Request) { + if IsInvalidLicense() { + util.WriteBadLicense(w) + return + } + method := "DeleteDocumentPage" p := request.GetPersister(r) @@ -354,6 +364,11 @@ func DeleteDocumentPage(w http.ResponseWriter, r *http.Request) { // DeleteDocumentPages batch deletes pages. func DeleteDocumentPages(w http.ResponseWriter, r *http.Request) { + if IsInvalidLicense() { + util.WriteBadLicense(w) + return + } + method := "DeleteDocumentPages" p := request.GetPersister(r) @@ -433,6 +448,11 @@ func DeleteDocumentPages(w http.ResponseWriter, r *http.Request) { // that this is a new revision. If the page is the first in a document // then the corresponding document title will also be changed. func UpdateDocumentPage(w http.ResponseWriter, r *http.Request) { + if IsInvalidLicense() { + util.WriteBadLicense(w) + return + } + method := "UpdateDocumentPage" p := request.GetPersister(r) params := mux.Vars(r) @@ -540,6 +560,11 @@ func UpdateDocumentPage(w http.ResponseWriter, r *http.Request) { // ChangeDocumentPageSequence will swap page sequence for a given number of pages. func ChangeDocumentPageSequence(w http.ResponseWriter, r *http.Request) { + if IsInvalidLicense() { + util.WriteBadLicense(w) + return + } + method := "ChangeDocumentPageSequence" p := request.GetPersister(r) @@ -598,6 +623,11 @@ func ChangeDocumentPageSequence(w http.ResponseWriter, r *http.Request) { // ChangeDocumentPageLevel handles page indent/outdent changes. func ChangeDocumentPageLevel(w http.ResponseWriter, r *http.Request) { + if IsInvalidLicense() { + util.WriteBadLicense(w) + return + } + method := "ChangeDocumentPageLevel" p := request.GetPersister(r) @@ -740,6 +770,11 @@ func GetPageMoveCopyTargets(w http.ResponseWriter, r *http.Request) { // GetDocumentRevisions returns all changes for a document. func GetDocumentRevisions(w http.ResponseWriter, r *http.Request) { + if IsInvalidLicense() { + util.WriteBadLicense(w) + return + } + method := "GetDocumentPageRevisions" p := request.GetPersister(r) @@ -770,6 +805,11 @@ func GetDocumentRevisions(w http.ResponseWriter, r *http.Request) { // GetDocumentPageRevisions returns all changes for a given page. func GetDocumentPageRevisions(w http.ResponseWriter, r *http.Request) { + if IsInvalidLicense() { + util.WriteBadLicense(w) + return + } + method := "GetDocumentPageRevisions" p := request.GetPersister(r) @@ -807,6 +847,11 @@ func GetDocumentPageRevisions(w http.ResponseWriter, r *http.Request) { // GetDocumentPageDiff returns HTML diff between two revisions of a given page. func GetDocumentPageDiff(w http.ResponseWriter, r *http.Request) { + if IsInvalidLicense() { + util.WriteBadLicense(w) + return + } + method := "GetDocumentPageDiff" p := request.GetPersister(r) diff --git a/core/api/endpoint/pin_endpoint.go b/core/api/endpoint/pin_endpoint.go index 04f1d1c7..be682241 100644 --- a/core/api/endpoint/pin_endpoint.go +++ b/core/api/endpoint/pin_endpoint.go @@ -28,6 +28,11 @@ import ( // AddPin saves pinned item. func AddPin(w http.ResponseWriter, r *http.Request) { + if IsInvalidLicense() { + util.WriteBadLicense(w) + return + } + method := "AddPin" p := request.GetPersister(r) params := mux.Vars(r) @@ -131,6 +136,11 @@ func GetUserPins(w http.ResponseWriter, r *http.Request) { // DeleteUserPin removes saved user pin. func DeleteUserPin(w http.ResponseWriter, r *http.Request) { + if IsInvalidLicense() { + util.WriteBadLicense(w) + return + } + method := "DeleteUserPin" p := request.GetPersister(r) params := mux.Vars(r) @@ -175,6 +185,11 @@ func DeleteUserPin(w http.ResponseWriter, r *http.Request) { // UpdatePinSequence records order of pinned items. func UpdatePinSequence(w http.ResponseWriter, r *http.Request) { + if IsInvalidLicense() { + util.WriteBadLicense(w) + return + } + method := "UpdatePinSequence" p := request.GetPersister(r) params := mux.Vars(r) diff --git a/core/api/endpoint/router.go b/core/api/endpoint/router.go index cb756b34..ed178d12 100644 --- a/core/api/endpoint/router.go +++ b/core/api/endpoint/router.go @@ -229,8 +229,10 @@ func init() { log.IfErr(Add(RoutePrefixPrivate, "documents/{documentID}/links", []string{"GET", "OPTIONS"}, nil, GetDocumentLinks)) // Global installation-wide config - log.IfErr(Add(RoutePrefixPrivate, "global", []string{"GET", "OPTIONS"}, nil, GetGlobalConfig)) - log.IfErr(Add(RoutePrefixPrivate, "global", []string{"PUT", "OPTIONS"}, nil, SaveGlobalConfig)) + log.IfErr(Add(RoutePrefixPrivate, "global/smtp", []string{"GET", "OPTIONS"}, nil, GetSMTPConfig)) + log.IfErr(Add(RoutePrefixPrivate, "global/smtp", []string{"PUT", "OPTIONS"}, nil, SaveSMTPConfig)) + log.IfErr(Add(RoutePrefixPrivate, "global/license", []string{"GET", "OPTIONS"}, nil, GetLicense)) + log.IfErr(Add(RoutePrefixPrivate, "global/license", []string{"PUT", "OPTIONS"}, nil, SaveLicense)) // Pinned items log.IfErr(Add(RoutePrefixPrivate, "pin/{userID}", []string{"POST", "OPTIONS"}, nil, AddPin)) diff --git a/core/api/endpoint/sections_endpoint.go b/core/api/endpoint/sections_endpoint.go index f297d815..eaaf8045 100644 --- a/core/api/endpoint/sections_endpoint.go +++ b/core/api/endpoint/sections_endpoint.go @@ -185,6 +185,11 @@ func RefreshSections(w http.ResponseWriter, r *http.Request) { // AddBlock inserts new reusable content block into database. func AddBlock(w http.ResponseWriter, r *http.Request) { + if IsInvalidLicense() { + util.WriteBadLicense(w) + return + } + method := "AddBlock" p := request.GetPersister(r) diff --git a/core/api/endpoint/server.go b/core/api/endpoint/server.go index 7684cb1b..0387940a 100644 --- a/core/api/endpoint/server.go +++ b/core/api/endpoint/server.go @@ -33,11 +33,21 @@ var port, certFile, keyFile, forcePort2SSL string var Product core.ProdInfo func init() { - Product = core.Product() + Product.Major = "0" + Product.Minor = "43" + Product.Patch = "0" + Product.Version = fmt.Sprintf("%s.%s.%s", Product.Major, Product.Minor, Product.Patch) + Product.Edition = "Community" + Product.Title = fmt.Sprintf("%s Edition", Product.Edition) + Product.License = core.License{} + Product.License.Valid = true + environment.GetString(&certFile, "cert", false, "the cert.pem file used for https", nil) environment.GetString(&keyFile, "key", false, "the key.pem file used for https", nil) environment.GetString(&port, "port", false, "http/https port number", nil) environment.GetString(&forcePort2SSL, "forcesslport", false, "redirect given http port number to TLS", nil) + + log.Info("Server.Init complete") } var testHost string // used during automated testing diff --git a/core/api/endpoint/templates_endpoint.go b/core/api/endpoint/templates_endpoint.go index 972fbdab..3f12455d 100644 --- a/core/api/endpoint/templates_endpoint.go +++ b/core/api/endpoint/templates_endpoint.go @@ -36,6 +36,11 @@ import ( // SaveAsTemplate saves existing document as a template. func SaveAsTemplate(w http.ResponseWriter, r *http.Request) { + if IsInvalidLicense() { + util.WriteBadLicense(w) + return + } + method := "SaveAsTemplate" p := request.GetPersister(r) diff --git a/core/api/endpoint/user_endpoint.go b/core/api/endpoint/user_endpoint.go index 5ababd20..120456d6 100644 --- a/core/api/endpoint/user_endpoint.go +++ b/core/api/endpoint/user_endpoint.go @@ -33,6 +33,11 @@ import ( // AddUser is the endpoint that enables an administrator to add a new user for their orgaisation. func AddUser(w http.ResponseWriter, r *http.Request) { + if IsInvalidLicense() { + util.WriteBadLicense(w) + return + } + method := "AddUser" p := request.GetPersister(r) diff --git a/core/api/entity/objects.go b/core/api/entity/objects.go index e5ffda5c..2e4b4014 100644 --- a/core/api/entity/objects.go +++ b/core/api/entity/objects.go @@ -341,6 +341,8 @@ type SiteMeta struct { URL string `json:"url"` AllowAnonymousAccess bool `json:"allowAnonymousAccess"` Version string `json:"version"` + Edition string `json:"edition"` + Valid bool `json:"valid"` } // Template is used to create a new document. diff --git a/core/api/util/writeHTTP.go b/core/api/util/writeHTTP.go index 68c50ed3..d0a21869 100644 --- a/core/api/util/writeHTTP.go +++ b/core/api/util/writeHTTP.go @@ -164,3 +164,17 @@ func WriteJSON(w http.ResponseWriter, v interface{}) { _, err = w.Write(j) log.IfErr(err) } + +// WriteBadLicense writes 402 when license is invalid +func WriteBadLicense(w http.ResponseWriter) { + w.Header().Set("Content-Type", "application/json; charset=utf-8") + w.WriteHeader(http.StatusPaymentRequired) + var e struct { + Reason string + } + e.Reason = "invalid or expired Documize license" + + j, _ := json.Marshal(e) + _, err := w.Write(j) + log.IfErr(err) +} diff --git a/core/product.go b/core/product.go index 287e6247..dcc653e9 100644 --- a/core/product.go +++ b/core/product.go @@ -11,7 +11,10 @@ package core -import "fmt" +import ( + "fmt" + "time" +) // ProdInfo describes a product type ProdInfo struct { @@ -21,16 +24,42 @@ type ProdInfo struct { Major string Minor string Patch string + License License } -// Product returns product edition details -func Product() (p ProdInfo) { - p.Major = "0" - p.Minor = "42" - p.Patch = "0" - p.Version = fmt.Sprintf("%s.%s.%s", p.Major, p.Minor, p.Patch) - p.Edition = "Community" - p.Title = fmt.Sprintf("%s Edition", p.Edition) - - return p +// License holds details of product license. +type License struct { + Name string `json:"name"` + Email string `json:"email"` + Edition string `json:"edition"` + Start time.Time `json:"start"` + End time.Time `json:"end"` + Seats int `json:"seats"` + Trial bool `json:"trial"` + Valid bool +} + +// IsEmpty determines if we have a license. +func (l *License) IsEmpty() bool { + return l.Seats == 0 && len(l.Name) == 0 && len(l.Email) == 0 && l.Start.Year() == 1 && l.End.Year() == 1 +} + +// Status returns formatted message stating if license is empty/populated and invalid/valid. +func (l *License) Status() string { + lp := "populated" + if l.IsEmpty() { + lp = "empty" + } + lv := "invalid" + if l.Valid { + lv = "valid" + } + + return fmt.Sprintf("License is %s and %s", lp, lv) +} + +// LicenseData holds encrypted data and is unpacked into License. +type LicenseData struct { + Key string `json:"key"` + Signature string `json:"signature"` }