mirror of
https://github.com/documize/community.git
synced 2025-07-23 07:09:43 +02:00
Fix an issue with Everyone permissions not being observed
This commit is contained in:
parent
91bab8c710
commit
9d8b1d2f3c
19 changed files with 102 additions and 94 deletions
10
README.md
10
README.md
|
@ -10,10 +10,10 @@ Documize is an intelligent document environment (IDE) for creating, securing and
|
|||
|
||||
## Why should I care?
|
||||
|
||||
Because maybe like us, you might be tired of:
|
||||
Because maybe like us, you're tired of:
|
||||
|
||||
* juggling WYSIWYG editors, wiki software and various document related solutions
|
||||
* playing document related email tennis with contributions, versions and feedback
|
||||
* juggling WYSIWYG editors, wiki software and other document related solutions
|
||||
* playing email tennis with documents, contributions, versions and feedback
|
||||
* sharing not-so-secure folders with external participants
|
||||
|
||||
Sound familiar? Read on.
|
||||
|
@ -38,7 +38,7 @@ Reusable templates and content blocks.
|
|||
|
||||
Documentation related tasking and delegation.
|
||||
|
||||
Integrations for embedding SaaS data within documents.
|
||||
Integrations for embedding SaaS data within documents, zero add-on/marketplace fees.
|
||||
|
||||
## What does it look like?
|
||||
|
||||
|
@ -63,7 +63,7 @@ Documize runs on the following:
|
|||
Documize is built with the following technologies:
|
||||
|
||||
- EmberJS (v2.18.0)
|
||||
- Go (v1.9.2)
|
||||
- Go (v1.9.3)
|
||||
|
||||
...and supports the following databases:
|
||||
|
||||
|
|
|
@ -234,9 +234,9 @@ func (s Scope) GetSpaceCategoryMembership(ctx domain.RequestContext, spaceID str
|
|||
SELECT id, refid, orgid, labelid, categoryid, documentid, created, revised FROM categorymember
|
||||
WHERE orgid=? AND labelid=?
|
||||
AND labelid IN (SELECT refid FROM permission WHERE orgid=? AND location='space' AND refid IN (
|
||||
SELECT refid from permission WHERE orgid=? AND who='user' AND whoid=? AND location='space' UNION ALL
|
||||
SELECT refid from permission WHERE orgid=? AND who='user' AND (whoid=? OR whoid='0') AND location='space' UNION ALL
|
||||
SELECT p.refid from permission p LEFT JOIN rolemember r ON p.whoid=r.roleid WHERE p.orgid=? AND p.who='role' AND p.location='space'
|
||||
AND p.action='view' AND r.userid=?
|
||||
AND p.action='view' AND (r.userid=? OR r.userid='0')
|
||||
))
|
||||
ORDER BY documentid`, ctx.OrgID, spaceID, ctx.OrgID, ctx.OrgID, ctx.UserID, ctx.OrgID, ctx.UserID)
|
||||
|
||||
|
|
|
@ -14,7 +14,6 @@ package document
|
|||
import (
|
||||
"database/sql"
|
||||
"encoding/json"
|
||||
"github.com/documize/community/model/user"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"sort"
|
||||
|
@ -34,6 +33,7 @@ import (
|
|||
pm "github.com/documize/community/model/permission"
|
||||
"github.com/documize/community/model/search"
|
||||
"github.com/documize/community/model/space"
|
||||
"github.com/documize/community/model/user"
|
||||
"github.com/documize/community/model/workflow"
|
||||
)
|
||||
|
||||
|
|
|
@ -111,9 +111,9 @@ func (s Scope) GetBySpace(ctx domain.RequestContext, spaceID string) (documents
|
|||
WHERE orgid=? AND template=0 AND labelid IN (
|
||||
SELECT refid FROM label WHERE orgid=? AND refid IN
|
||||
(SELECT refid FROM permission WHERE orgid=? AND location='space' AND refid=? AND refid IN (
|
||||
SELECT refid from permission WHERE orgid=? AND who='user' AND whoid=? AND location='space' UNION ALL
|
||||
SELECT refid from permission WHERE orgid=? AND who='user' AND (whoid=? OR whoid='0') AND location='space' UNION ALL
|
||||
SELECT p.refid from permission p LEFT JOIN rolemember r ON p.whoid=r.roleid WHERE p.orgid=?
|
||||
AND p.who='role' AND p.location='space' AND p.refid=? AND p.action='view' AND r.userid=?
|
||||
AND p.who='role' AND p.location='space' AND p.refid=? AND p.action='view' AND (r.userid=? OR r.userid='0')
|
||||
))
|
||||
)
|
||||
ORDER BY title`, ctx.OrgID, ctx.OrgID, ctx.OrgID, spaceID, ctx.OrgID, ctx.UserID, ctx.OrgID, spaceID, ctx.UserID)
|
||||
|
@ -136,9 +136,9 @@ func (s Scope) Templates(ctx domain.RequestContext) (documents []doc.Document, e
|
|||
(
|
||||
SELECT refid FROM label WHERE orgid=?
|
||||
AND refid IN (SELECT refid FROM permission WHERE orgid=? AND location='space' AND refid IN (
|
||||
SELECT refid from permission WHERE orgid=? AND who='user' AND whoid=? AND location='space'
|
||||
SELECT refid from permission WHERE orgid=? AND who='user' AND (whoid=? OR whoid='0') AND location='space'
|
||||
UNION ALL
|
||||
SELECT p.refid from permission p LEFT JOIN rolemember r ON p.whoid=r.roleid WHERE p.orgid=? AND p.who='role' AND p.location='space' AND p.action='view' AND r.userid=?
|
||||
SELECT p.refid from permission p LEFT JOIN rolemember r ON p.whoid=r.roleid WHERE p.orgid=? AND p.who='role' AND p.location='space' AND p.action='view' AND (r.userid=? OR r.userid='0')
|
||||
))
|
||||
)
|
||||
ORDER BY title`, ctx.OrgID, ctx.OrgID, ctx.OrgID, ctx.OrgID, ctx.UserID, ctx.OrgID, ctx.UserID)
|
||||
|
@ -158,9 +158,9 @@ func (s Scope) TemplatesBySpace(ctx domain.RequestContext, spaceID string) (docu
|
|||
(
|
||||
SELECT refid FROM label WHERE orgid=?
|
||||
AND refid IN (SELECT refid FROM permission WHERE orgid=? AND location='space' AND refid IN (
|
||||
SELECT refid from permission WHERE orgid=? AND who='user' AND whoid=? AND location='space'
|
||||
SELECT refid from permission WHERE orgid=? AND who='user' AND (whoid=? OR whoid='0') AND location='space'
|
||||
UNION ALL
|
||||
SELECT p.refid from permission p LEFT JOIN rolemember r ON p.whoid=r.roleid WHERE p.orgid=? AND p.who='role' AND p.location='space' AND p.action='view' AND r.userid=?
|
||||
SELECT p.refid from permission p LEFT JOIN rolemember r ON p.whoid=r.roleid WHERE p.orgid=? AND p.who='role' AND p.location='space' AND p.action='view' AND (r.userid=? OR r.userid='0')
|
||||
))
|
||||
)
|
||||
ORDER BY title`, ctx.OrgID, spaceID, ctx.OrgID, ctx.OrgID, ctx.OrgID, ctx.UserID, ctx.OrgID, ctx.UserID)
|
||||
|
@ -201,9 +201,9 @@ func (s Scope) DocumentList(ctx domain.RequestContext) (documents []doc.Document
|
|||
(
|
||||
SELECT refid FROM label WHERE orgid=?
|
||||
AND refid IN (SELECT refid FROM permission WHERE orgid=? AND location='space' AND refid IN (
|
||||
SELECT refid from permission WHERE orgid=? AND who='user' AND whoid=? AND location='space'
|
||||
SELECT refid from permission WHERE orgid=? AND who='user' AND (whoid=? OR whoid='0') AND location='space'
|
||||
UNION ALL
|
||||
SELECT p.refid from permission p LEFT JOIN rolemember r ON p.whoid=r.roleid WHERE p.orgid=? AND p.who='role' AND p.location='space' AND p.action='view' AND r.userid=?
|
||||
SELECT p.refid from permission p LEFT JOIN rolemember r ON p.whoid=r.roleid WHERE p.orgid=? AND p.who='role' AND p.location='space' AND p.action='view' AND (r.userid=? OR r.userid='0')
|
||||
))
|
||||
)
|
||||
ORDER BY title`, ctx.OrgID, ctx.OrgID, ctx.OrgID, ctx.OrgID, ctx.UserID, ctx.OrgID, ctx.UserID)
|
||||
|
|
|
@ -164,9 +164,10 @@ func (s Scope) SearchCandidates(ctx domain.RequestContext, keywords string) (doc
|
|||
(
|
||||
SELECT refid FROM label WHERE orgid=?
|
||||
AND refid IN (SELECT refid FROM permission WHERE orgid=? AND location='space' AND refid IN (
|
||||
SELECT refid from permission WHERE orgid=? AND who='user' AND whoid=? AND location='space'
|
||||
SELECT refid from permission WHERE orgid=? AND who='user' AND (whoid=? OR whoid='0') AND location='space'
|
||||
UNION ALL
|
||||
SELECT p.refid from permission p LEFT JOIN rolemember r ON p.whoid=r.roleid WHERE p.orgid=? AND p.who='role' AND p.location='space' AND p.action='view' AND r.userid=?
|
||||
SELECT p.refid from permission p LEFT JOIN rolemember r ON p.whoid=r.roleid WHERE p.orgid=? AND p.who='role'
|
||||
AND p.location='space' AND p.action='view' AND (r.userid=? OR r.userid='0')
|
||||
))
|
||||
)
|
||||
ORDER BY title`, ctx.OrgID, ctx.OrgID, ctx.OrgID, ctx.OrgID, ctx.UserID, ctx.OrgID, ctx.UserID)
|
||||
|
@ -201,9 +202,10 @@ func (s Scope) SearchCandidates(ctx domain.RequestContext, keywords string) (doc
|
|||
(
|
||||
SELECT refid FROM label WHERE orgid=?
|
||||
AND refid IN (SELECT refid FROM permission WHERE orgid=? AND location='space' AND refid IN (
|
||||
SELECT refid from permission WHERE orgid=? AND who='user' AND whoid=? AND location='space'
|
||||
SELECT refid from permission WHERE orgid=? AND who='user' AND (whoid=? OR whoid='0') AND location='space'
|
||||
UNION ALL
|
||||
SELECT p.refid from permission p LEFT JOIN rolemember r ON p.whoid=r.roleid WHERE p.orgid=? AND p.who='role' AND p.location='space' AND p.action='view' AND r.userid=?
|
||||
SELECT p.refid from permission p LEFT JOIN rolemember r ON p.whoid=r.roleid WHERE p.orgid=? AND p.who='role'
|
||||
AND p.location='space' AND p.action='view' AND (r.userid=? OR r.userid='0')
|
||||
))
|
||||
)
|
||||
ORDER BY p.title`, ctx.OrgID, ctx.OrgID, ctx.OrgID, ctx.OrgID, ctx.UserID, ctx.OrgID, ctx.UserID)
|
||||
|
@ -238,9 +240,10 @@ func (s Scope) SearchCandidates(ctx domain.RequestContext, keywords string) (doc
|
|||
(
|
||||
SELECT refid FROM label WHERE orgid=?
|
||||
AND refid IN (SELECT refid FROM permission WHERE orgid=? AND location='space' AND refid IN (
|
||||
SELECT refid from permission WHERE orgid=? AND who='user' AND whoid=? AND location='space'
|
||||
SELECT refid from permission WHERE orgid=? AND who='user' AND (whoid=? OR whoid='0') AND location='space'
|
||||
UNION ALL
|
||||
SELECT p.refid from permission p LEFT JOIN rolemember r ON p.whoid=r.roleid WHERE p.orgid=? AND p.who='role' AND p.location='space' AND p.action='view' AND r.userid=?
|
||||
SELECT p.refid from permission p LEFT JOIN rolemember r ON p.whoid=r.roleid WHERE p.orgid=? AND p.who='role'
|
||||
AND p.location='space' AND p.action='view' AND (r.userid=? OR r.userid='0')
|
||||
))
|
||||
)
|
||||
ORDER BY a.filename`, ctx.OrgID, ctx.OrgID, ctx.OrgID, ctx.OrgID, ctx.UserID, ctx.OrgID, ctx.UserID)
|
||||
|
|
|
@ -64,7 +64,7 @@ func (s Scope) GetUserSpacePermissions(ctx domain.RequestContext, spaceID string
|
|||
SELECT p.id, p.orgid, p.who, p.whoid, p.action, p.scope, p.location, p.refid
|
||||
FROM permission p LEFT JOIN rolemember r ON p.whoid=r.roleid WHERE p.orgid=? AND p.location='space' AND refid=?
|
||||
AND p.who='role' AND (r.userid=? OR r.userid='0')`,
|
||||
ctx.OrgID, spaceID, ctx.UserID, ctx.OrgID, spaceID, ctx.OrgID)
|
||||
ctx.OrgID, spaceID, ctx.UserID, ctx.OrgID, spaceID, ctx.UserID)
|
||||
|
||||
if err == sql.ErrNoRows {
|
||||
err = nil
|
||||
|
|
|
@ -222,7 +222,7 @@ func (s Scope) matchFullText(ctx domain.RequestContext, keywords, itemType strin
|
|||
(
|
||||
SELECT refid FROM label WHERE orgid=?
|
||||
AND refid IN (SELECT refid FROM permission WHERE orgid=? AND location='space' AND refid IN (
|
||||
SELECT refid from permission WHERE orgid=? AND who='user' AND whoid=? AND location='space'
|
||||
SELECT refid from permission WHERE orgid=? AND who='user' AND (whoid=? OR whoid='0') AND location='space'
|
||||
UNION ALL
|
||||
SELECT p.refid from permission p LEFT JOIN rolemember r ON p.whoid=r.roleid WHERE p.orgid=? AND p.who='role' AND p.location='space' AND p.action='view' AND r.userid=?
|
||||
))
|
||||
|
@ -279,9 +279,10 @@ func (s Scope) matchLike(ctx domain.RequestContext, keywords, itemType string) (
|
|||
(
|
||||
SELECT refid FROM label WHERE orgid=?
|
||||
AND refid IN (SELECT refid FROM permission WHERE orgid=? AND location='space' AND refid IN (
|
||||
SELECT refid from permission WHERE orgid=? AND who='user' AND whoid=? AND location='space'
|
||||
SELECT refid from permission WHERE orgid=? AND who='user' AND (whoid=? OR whoid='0') AND location='space'
|
||||
UNION ALL
|
||||
SELECT p.refid from permission p LEFT JOIN rolemember r ON p.whoid=r.roleid WHERE p.orgid=? AND p.who='role' AND p.location='space' AND p.action='view' AND r.userid=?
|
||||
SELECT p.refid from permission p LEFT JOIN rolemember r ON p.whoid=r.roleid WHERE p.orgid=? AND p.who='role'
|
||||
AND p.location='space' AND p.action='view' AND (r.userid=? OR r.userid='0')
|
||||
))
|
||||
)
|
||||
AND s.content LIKE ?`
|
||||
|
|
|
@ -642,7 +642,7 @@ func (h *Handler) AcceptInvitation(w http.ResponseWriter, r *http.Request) {
|
|||
|
||||
u, err := h.Store.User.GetBySerial(ctx, model.Serial)
|
||||
if err != nil && err == sql.ErrNoRows {
|
||||
response.WriteDuplicateError(w, method, "user")
|
||||
response.WriteNotFoundError(w, method, "user")
|
||||
h.Runtime.Log.Error(method, err)
|
||||
return
|
||||
}
|
||||
|
@ -650,6 +650,7 @@ func (h *Handler) AcceptInvitation(w http.ResponseWriter, r *http.Request) {
|
|||
// AcceptShare does not authenticate the user hence the context needs to set up
|
||||
ctx.UserID = u.RefID
|
||||
|
||||
// Prepare user data
|
||||
u.Firstname = model.Firstname
|
||||
u.Lastname = model.Lastname
|
||||
u.Initials = stringutil.MakeInitials(u.Firstname, u.Lastname)
|
||||
|
@ -670,7 +671,6 @@ func (h *Handler) AcceptInvitation(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
|
||||
salt := secrets.GenerateSalt()
|
||||
|
||||
err = h.Store.User.UpdateUserPassword(ctx, u.RefID, salt, secrets.GeneratePassword(model.Password, salt))
|
||||
if err != nil {
|
||||
ctx.Transaction.Rollback()
|
||||
|
@ -679,10 +679,12 @@ func (h *Handler) AcceptInvitation(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
h.Store.Audit.Record(ctx, audit.EventTypeSpaceJoin)
|
||||
|
||||
ctx.Transaction.Commit()
|
||||
|
||||
h.Store.Audit.Record(ctx, audit.EventTypeSpaceJoin)
|
||||
|
||||
// We send back POJO and not fully authenticated user object as
|
||||
// SSO should take place thereafter
|
||||
response.WriteJSON(w, u)
|
||||
}
|
||||
|
||||
|
@ -704,10 +706,10 @@ func (h *Handler) Invite(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
if sp.UserID != ctx.UserID {
|
||||
response.WriteForbiddenError(w)
|
||||
return
|
||||
}
|
||||
// if sp.UserID != ctx.UserID {
|
||||
// response.WriteForbiddenError(w)
|
||||
// return
|
||||
// }
|
||||
|
||||
defer streamutil.Close(r.Body)
|
||||
body, err := ioutil.ReadAll(r.Body)
|
||||
|
|
|
@ -97,7 +97,7 @@ func (s Scope) GetByToken(ctx domain.RequestContext, token string) (u user.User,
|
|||
// This occurs when we you share a folder with a new user and they have to complete
|
||||
// the onboarding process.
|
||||
func (s Scope) GetBySerial(ctx domain.RequestContext, serial string) (u user.User, err error) {
|
||||
err = s.Runtime.Db.Get("SELECT id, refid, firstname, lastname, email, initials, global, password, salt, reset, created, revised FROM user WHERE salt=?", serial)
|
||||
err = s.Runtime.Db.Get(&u, "SELECT id, refid, firstname, lastname, email, initials, global, password, salt, reset, created, revised FROM user WHERE salt=?", serial)
|
||||
|
||||
if err != nil {
|
||||
err = errors.Wrap(err, fmt.Sprintf("execute user select by serial %s", serial))
|
||||
|
|
|
@ -18,9 +18,6 @@ export default Component.extend({
|
|||
documentService: service('document'),
|
||||
appMeta: service(),
|
||||
hasAttachments: notEmpty('files'),
|
||||
canShow: computed('permissions', 'files', function() {
|
||||
return this.get('files.length') > 0 || this.get('permissions.documentEdit');
|
||||
}),
|
||||
canEdit: computed('permissions', 'document.protection', function() {
|
||||
return this.get('document.protection') !== this.get('constants').ProtectionType.Lock && this.get('permissions.documentEdit');
|
||||
}),
|
||||
|
|
|
@ -114,7 +114,7 @@ export default Component.extend({
|
|||
$(".stage-3").fadeIn();
|
||||
// $("#spinner-1").show();
|
||||
|
||||
var payload = '{ "Password": "' + $("#stage-2-password").val() + '", "Serial": "' + self.serial + '", "Firstname": "' + $("#stage-1-firstname").val() + '", "Lastname": "' + $("#stage-1-lastname").val() + '" }';
|
||||
var payload = '{ "password": "' + $("#stage-2-password").val() + '", "serial": "' + self.serial + '", "firstname": "' + $("#stage-1-firstname").val() + '", "lastname": "' + $("#stage-1-lastname").val() + '" }';
|
||||
var password = $("#stage-2-password").val();
|
||||
|
||||
self.get('folderService').onboard(self.folderId, payload).then(function(user) {
|
||||
|
|
|
@ -57,7 +57,6 @@ export default Component.extend(ModalMixin, TooltipMixin, AuthMixin, {
|
|||
|
||||
didInsertElement() {
|
||||
this._super(...arguments);
|
||||
|
||||
this.modalInputFocus('#document-template-modal', '#new-template-name');
|
||||
},
|
||||
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row no-gutters">
|
||||
<div class="row no-gutters mb-5">
|
||||
<div class="col-12">
|
||||
<div class="text-center non-printable document-tabnav">
|
||||
<ul class="tabnav-control">
|
||||
|
|
|
@ -10,7 +10,6 @@
|
|||
// https://documize.com
|
||||
|
||||
import { htmlSafe } from '@ember/string';
|
||||
|
||||
import { resolve } from 'rsvp';
|
||||
import Service, { inject as service } from '@ember/service';
|
||||
import config from '../config/environment';
|
||||
|
|
|
@ -95,7 +95,7 @@ export default BaseService.extend({
|
|||
});
|
||||
},
|
||||
|
||||
// reloads and caches folders.
|
||||
// reloads and caches folders
|
||||
reload() {
|
||||
return this.get('ajax').request(`space`, {
|
||||
method: "GET"
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
{{#if canShow}}
|
||||
<div class="view-attachment mt-5">
|
||||
{{#if hasAttachments}}
|
||||
<ul class="list">
|
||||
|
@ -16,6 +15,8 @@
|
|||
</li>
|
||||
{{/each}}
|
||||
</ul>
|
||||
{{else}}
|
||||
<p>No attachments found</p>
|
||||
{{/if}}
|
||||
{{#if canEdit}}
|
||||
<div class="upload-document-files">
|
||||
|
@ -27,4 +28,3 @@
|
|||
{{#ui/ui-dialog title="Delete Attachment" confirmCaption="Delete" buttonType="btn-danger" show=showDialog onAction=(action 'onDelete')}}
|
||||
<p>Are you sure you want to delete {{deleteAttachment.name}}?</p>
|
||||
{{/ui/ui-dialog}}
|
||||
{{/if}}
|
|
@ -18,6 +18,7 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{#if permissions.documentEdit}}
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<div class="form-group">
|
||||
|
@ -40,8 +41,8 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
{{else}}
|
||||
<p>No revisions made</p>
|
||||
{{/if}}
|
||||
</div>
|
||||
|
||||
|
|
|
@ -1,7 +1,13 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"target": "es6",
|
||||
"experimentalDecorators": true
|
||||
"experimentalDecorators": true,
|
||||
"allowSyntheticDefaultImports": true
|
||||
},
|
||||
"exclude": ["node_modules", "bower_components", "tmp", "vendor", ".git", "dist", "dist-prod", "gui/node_modules", "gui/dist", "gui/dist-prod", "gui/tmp"]
|
||||
"exclude": ["node_modules", "bower_components", "tmp", "vendor", ".git", "dist", "dist-prod", "gui/node_modules", "gui/dist", "gui/dist-prod", "gui/tmp"],
|
||||
"typeAcquisition": {
|
||||
"include": [
|
||||
"underscore"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -73,7 +73,7 @@ func RegisterEndpoints(rt *env.Runtime, s *domain.Store) {
|
|||
Add(rt, RoutePrefixPublic, "validate", []string{"GET", "OPTIONS"}, nil, auth.ValidateToken)
|
||||
Add(rt, RoutePrefixPublic, "forgot", []string{"POST", "OPTIONS"}, nil, user.ForgotPassword)
|
||||
Add(rt, RoutePrefixPublic, "reset/{token}", []string{"POST", "OPTIONS"}, nil, user.ResetPassword)
|
||||
Add(rt, RoutePrefixPublic, "share/{folderID}", []string{"POST", "OPTIONS"}, nil, space.AcceptInvitation)
|
||||
Add(rt, RoutePrefixPublic, "share/{spaceID}", []string{"POST", "OPTIONS"}, nil, space.AcceptInvitation)
|
||||
Add(rt, RoutePrefixPublic, "attachments/{orgID}/{attachmentID}", []string{"GET", "OPTIONS"}, nil, attachment.Download)
|
||||
Add(rt, RoutePrefixPublic, "version", []string{"GET", "OPTIONS"}, nil, func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Write([]byte(rt.Product.Version))
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue