-
Notifications
You must be signed in to change notification settings - Fork 58
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Convert Autolink plugin into an App, and introduce autolink edit modal #159
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,11 +1,26 @@ | ||
module github.com/mattermost/mattermost-plugin-autolink | ||
|
||
go 1.12 | ||
go 1.16 | ||
|
||
require ( | ||
github.com/gorilla/mux v1.7.4 | ||
github.com/mattermost/mattermost-server/v5 v5.28.1 | ||
github.com/mholt/archiver/v3 v3.3.0 | ||
github.com/go-sql-driver/mysql v1.6.0 // indirect | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is this |
||
github.com/gorilla/mux v1.8.0 | ||
github.com/hashicorp/go-hclog v0.16.0 // indirect | ||
github.com/hashicorp/go-plugin v1.4.1 // indirect | ||
github.com/klauspost/compress v1.12.1 // indirect | ||
github.com/klauspost/cpuid/v2 v2.0.6 // indirect | ||
github.com/lib/pq v1.10.1 // indirect | ||
github.com/mattermost/mattermost-plugin-apps v0.4.1-0.20210424000506-01c57929151d | ||
github.com/mattermost/mattermost-server/v5 v5.3.2-0.20210413123336-5f2c26dbda0a | ||
github.com/mholt/archiver/v3 v3.5.0 | ||
github.com/pelletier/go-toml v1.9.0 // indirect | ||
github.com/pierrec/lz4/v4 v4.1.6 // indirect | ||
github.com/pkg/errors v0.9.1 | ||
github.com/stretchr/testify v1.6.1 | ||
github.com/rs/xid v1.3.0 // indirect | ||
github.com/stretchr/testify v1.7.0 | ||
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b // indirect | ||
golang.org/x/net v0.0.0-20210423184538-5f58ad60dda6 // indirect | ||
golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7 // indirect | ||
google.golang.org/genproto v0.0.0-20210423144448-3a41ef94ed2b // indirect | ||
google.golang.org/grpc v1.37.0 // indirect | ||
) |
Large diffs are not rendered by default.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,172 @@ | ||
package autolinkapp | ||
|
||
import ( | ||
"bytes" | ||
"encoding/json" | ||
"io/ioutil" | ||
"net/http" | ||
|
||
"github.com/gorilla/mux" | ||
"github.com/pkg/errors" | ||
|
||
"github.com/mattermost/mattermost-plugin-apps/apps" | ||
"github.com/mattermost/mattermost-plugin-apps/server/utils/httputils" | ||
"github.com/mattermost/mattermost-plugin-autolink/server/autolink" | ||
) | ||
|
||
type Store interface { | ||
GetLinks() []autolink.Autolink | ||
SaveLinks([]autolink.Autolink) error | ||
} | ||
|
||
type Service interface { | ||
GetPluginURL() string | ||
IsAuthorizedAdmin(userID string) (bool, error) | ||
} | ||
|
||
type app struct { | ||
store Store | ||
service Service | ||
} | ||
|
||
const ( | ||
appID = "com.mattermost.autolink" | ||
appDisplayName = "Autolink" | ||
|
||
autolinkCommand = "autolink-app" | ||
|
||
appRoute = "/app/v1" | ||
manifestRoute = "/manifest" | ||
bindingsRoute = "/bindings" | ||
iconRoute = "/public/icon.png" // Served from the plugin's public folder | ||
|
||
editLinksRoute = "/edit-links" | ||
editLinksCommandRoute = "/edit-links-command" | ||
) | ||
|
||
func RegisterHandler(root *mux.Router, store Store, service Service) { | ||
a := &app{ | ||
store: store, | ||
service: service, | ||
} | ||
|
||
appRouter := root.PathPrefix(appRoute).Subrouter() | ||
appRouter.HandleFunc(manifestRoute, a.handleManifest).Methods(http.MethodGet) | ||
|
||
adminRoutes := appRouter.PathPrefix("").Subrouter() | ||
adminRoutes.Use(a.adminRequired) | ||
|
||
adminRoutes.HandleFunc(bindingsRoute, a.handleBindings).Methods(http.MethodPost) | ||
adminRoutes.HandleFunc(editLinksRoute+"/form", a.handleFormFetch).Methods(http.MethodPost) | ||
adminRoutes.HandleFunc(editLinksRoute+"/submit", a.handleFormSubmit).Methods(http.MethodPost) | ||
adminRoutes.HandleFunc(editLinksCommandRoute+"/submit", a.handleCommandSubmit).Methods(http.MethodPost) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is this really There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hmm that was happening before and I thought I fixed that. Not sure how/why it's working |
||
} | ||
|
||
func (a *app) handleManifest(w http.ResponseWriter, r *http.Request) { | ||
pluginURL := a.service.GetPluginURL() | ||
rootURL := pluginURL + appRoute | ||
|
||
manifest := apps.Manifest{ | ||
AppID: appID, | ||
DisplayName: appDisplayName, | ||
AppType: apps.AppTypeHTTP, | ||
HTTPRootURL: rootURL, | ||
RequestedPermissions: apps.Permissions{ | ||
apps.PermissionActAsBot, | ||
}, | ||
RequestedLocations: apps.Locations{ | ||
apps.LocationCommand, | ||
}, | ||
} | ||
|
||
httputils.WriteJSON(w, manifest) | ||
} | ||
|
||
func (a *app) handleBindings(w http.ResponseWriter, r *http.Request) { | ||
call := &apps.CallRequest{} | ||
err := json.NewDecoder(r.Body).Decode(call) | ||
if err != nil { | ||
httputils.WriteJSON(w, apps.NewErrorCallResponse(errors.Wrap(err, "failed to decode call request body"))) | ||
return | ||
} | ||
|
||
icon := a.service.GetPluginURL() + iconRoute | ||
resp := &apps.CallResponse{ | ||
Type: apps.CallResponseTypeOK, | ||
Data: []apps.Binding{ | ||
{ | ||
Location: apps.LocationCommand, | ||
Bindings: []*apps.Binding{ | ||
{ | ||
Icon: icon, | ||
Label: autolinkCommand, | ||
Location: autolinkCommand, | ||
Description: appDisplayName, | ||
Hint: "[edit]", | ||
Bindings: []*apps.Binding{ | ||
{ | ||
Location: "edit", | ||
Label: "edit", | ||
Form: &apps.Form{Fields: []*apps.Field{}}, | ||
hanzei marked this conversation as resolved.
Show resolved
Hide resolved
|
||
Call: &apps.Call{ | ||
Path: editLinksCommandRoute, | ||
}, | ||
}, | ||
}, | ||
}, | ||
}, | ||
}, | ||
}, | ||
} | ||
|
||
httputils.WriteJSON(w, resp) | ||
} | ||
|
||
func (a *app) handleCommandSubmit(w http.ResponseWriter, r *http.Request) { | ||
resp := a.getEmptyFormResponse() | ||
httputils.WriteJSON(w, resp) | ||
} | ||
|
||
func (a *app) handleIcon(w http.ResponseWriter, r *http.Request) { | ||
resp := a.getEmptyFormResponse() | ||
httputils.WriteJSON(w, resp) | ||
} | ||
Comment on lines
+130
to
+133
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Unused? |
||
|
||
func (a *app) adminRequired(next http.Handler) http.Handler { | ||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { | ||
b, err := ioutil.ReadAll(r.Body) | ||
if err != nil { | ||
httputils.WriteJSON(w, apps.NewErrorCallResponse(errors.Wrap(err, "failed to read call request body"))) | ||
return | ||
} | ||
|
||
r.Body.Close() | ||
r.Body = ioutil.NopCloser(bytes.NewBuffer(b)) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why is this needed? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm reading from the body in this middleware, and want the http handlers to be able to read from the body as well. I don't like this solution There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is the approach from servicenow suitable here? https://github.com/mattermost/mattermost-app-servicenow/blob/5c160ea3d7c07017a5b1327c1a3c0a9ec5062c53/routers/mattermost/mattermost.go#L43-L66 |
||
|
||
call := &apps.CallRequest{} | ||
err = json.Unmarshal(b, call) | ||
if err != nil { | ||
httputils.WriteJSON(w, apps.NewErrorCallResponse(errors.Wrap(err, "failed to decode call request body"))) | ||
return | ||
} | ||
|
||
userID := call.Context.ActingUserID | ||
if userID == "" { | ||
httputils.WriteJSON(w, apps.NewErrorCallResponse(errors.New("no acting user id provided"))) | ||
return | ||
} | ||
|
||
authorized, err := a.service.IsAuthorizedAdmin(userID) | ||
if err != nil { | ||
httputils.WriteJSON(w, apps.NewErrorCallResponse(errors.Wrap(err, "not authorized"))) | ||
return | ||
} | ||
|
||
if !authorized { | ||
httputils.WriteJSON(w, apps.NewErrorCallResponse(errors.New("not authorized"))) | ||
return | ||
} | ||
|
||
next.ServeHTTP(w, r) | ||
}) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's stick with the starter template
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@hanzei The code was originally putting the
icon.png
file into thedist
folder, and not in thedist/public
folder. This was how I was able to get the icon in the right folder.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You are using a mac, right? Could you please test my code?