Skip to content
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

[GH-207] Added CRUD operations in autolink plugin #213

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
83 changes: 80 additions & 3 deletions server/api/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"github.com/pkg/errors"

"github.com/mattermost/mattermost-plugin-autolink/server/autolink"
"github.com/mattermost/mattermost-plugin-autolink/server/autolinkclient"
)

type Store interface {
Expand All @@ -34,7 +35,10 @@ func NewHandler(store Store, authorization Authorization) *Handler {
root := mux.NewRouter()
api := root.PathPrefix("/api/v1").Subrouter()
api.Use(h.adminOrPluginRequired)
api.HandleFunc("/link", h.setLink).Methods("POST")
link := api.PathPrefix("/link").Subrouter()
link.HandleFunc("", h.setLink).Methods(http.MethodPost)
link.HandleFunc("", h.deleteLink).Methods(http.MethodDelete)
link.HandleFunc("", h.getLinks).Methods(http.MethodGet)

api.Handle("{anything:.*}", http.NotFoundHandler())

Expand Down Expand Up @@ -98,7 +102,7 @@ func (h *Handler) setLink(w http.ResponseWriter, r *http.Request) {
found := false
changed := false
for i := range links {
if links[i].Name == newLink.Name || links[i].Pattern == newLink.Pattern {
if links[i].Name == newLink.Name {
if !links[i].Equals(newLink) {
links[i] = newLink
changed = true
Expand All @@ -114,12 +118,85 @@ func (h *Handler) setLink(w http.ResponseWriter, r *http.Request) {
status := http.StatusNotModified
if changed {
if err := h.store.SaveLinks(links); err != nil {
h.handleError(w, errors.Wrap(err, "unable to save link"))
h.handleError(w, errors.Wrap(err, "unable to save the link"))
return
}
status = http.StatusOK
}

ReturnStatusOK(status, w)
}

func (h *Handler) deleteLink(w http.ResponseWriter, r *http.Request) {
autolinkName := r.URL.Query().Get(autolinkclient.AutolinkNameQueryParam)
if autolinkName == "" {
h.handleError(w, errors.New("autolink name or pattern should not be empty"))
Kshitij-Katiyar marked this conversation as resolved.
Show resolved Hide resolved
return
}

links := h.store.GetLinks()
found := false
for i := 0; i < len(links); i++ {
if links[i].Name == autolinkName {
links = append(links[:i], links[i+1:]...)
found = true
Kshitij-Katiyar marked this conversation as resolved.
Show resolved Hide resolved
Kshitij-Katiyar marked this conversation as resolved.
Show resolved Hide resolved
}
}

status := http.StatusNotModified
if found {
if err := h.store.SaveLinks(links); err != nil {
h.handleError(w, errors.Wrap(err, "unable to save the link"))
return
}
status = http.StatusOK
}

ReturnStatusOK(status, w)
}

func (h *Handler) getLinks(w http.ResponseWriter, r *http.Request) {
links := h.store.GetLinks()

autolinkName := r.URL.Query().Get(autolinkclient.AutolinkNameQueryParam)
if autolinkName == "" {
h.handleSendingJSONContent(w, links)
return
}

found := false
var autolinks []autolink.Autolink
for _, link := range links {
if link.Name == autolinkName {
autolinks = append(autolinks, link)
found = true
}
}

if !found {
h.handleError(w, errors.Errorf("no autolink found with name %s", autolinkName))
return
}
Kshitij-Katiyar marked this conversation as resolved.
Show resolved Hide resolved

h.handleSendingJSONContent(w, autolinks)
return
}

func (h *Handler) handleSendingJSONContent(w http.ResponseWriter, v interface{}) {
w.Header().Set("Content-Type", "application/json")
b, err := json.Marshal(v)
if err != nil {
h.handleError(w, errors.Wrap(err, "failed to marshal JSON response"))
return
}

if _, err = w.Write(b); err != nil {
h.handleError(w, errors.Wrap(err, "failed to write JSON response"))
return
}
}

func ReturnStatusOK(status int, w http.ResponseWriter) {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(status)
_, _ = w.Write([]byte(`{"status": "OK"}`))
Expand Down
71 changes: 66 additions & 5 deletions server/autolinkclient/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,15 @@ import (
"fmt"
"io/ioutil"
"net/http"
"net/url"

"github.com/mattermost/mattermost-plugin-autolink/server/autolink"
)

const autolinkPluginID = "mattermost-autolink"
const (
autolinkPluginID = "mattermost-autolink"
AutolinkNameQueryParam = "autolinkName"
)

type PluginAPI interface {
PluginHTTP(*http.Request) *http.Response
Expand Down Expand Up @@ -45,22 +49,79 @@ func (c *Client) Add(links ...autolink.Autolink) error {
return err
}

req, err := http.NewRequest("POST", "/"+autolinkPluginID+"/api/v1/link", bytes.NewReader(linkBytes))
resp, err := c.call("/"+autolinkPluginID+"/api/v1/link", http.MethodPost, linkBytes, nil)
Kshitij-Katiyar marked this conversation as resolved.
Show resolved Hide resolved
if err != nil {
return err
}

resp, err := c.Do(req)
if resp.StatusCode != http.StatusOK {
respBody, _ := ioutil.ReadAll(resp.Body)
return fmt.Errorf("unable to add the link %s. Error: %v, %v", link.Name, resp.StatusCode, string(respBody))
}
}

return nil
}

func (c *Client) Delete(links ...string) error {
for _, link := range links {
queryParams := url.Values{
AutolinkNameQueryParam: {link},
}

resp, err := c.call("/"+autolinkPluginID+"/api/v1/link", http.MethodDelete, nil, queryParams)
Kshitij-Katiyar marked this conversation as resolved.
Show resolved Hide resolved
if err != nil {
return err
}
defer resp.Body.Close()
Kshitij-Katiyar marked this conversation as resolved.
Show resolved Hide resolved

if resp.StatusCode != http.StatusOK {
respBody, _ := ioutil.ReadAll(resp.Body)
return fmt.Errorf("unable to install autolink. Error: %v, %v", resp.StatusCode, string(respBody))
return fmt.Errorf("unable to delete the link %s. Error: %v, %v", link, resp.StatusCode, string(respBody))
}
}

return nil
}

func (c *Client) Get(autolinkName string) ([]*autolink.Autolink, error) {
Kshitij-Katiyar marked this conversation as resolved.
Show resolved Hide resolved
queryParams := url.Values{
AutolinkNameQueryParam: {autolinkName},
}

resp, err := c.call("/"+autolinkPluginID+"/api/v1/link", http.MethodGet, nil, queryParams)
if err != nil {
return nil, err
}

var respBody []byte
if resp.StatusCode != http.StatusOK {
respBody, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, err
}
return nil, fmt.Errorf("unable to get the link %s. Error: %v, %v", autolinkName, resp.StatusCode, string(respBody))
}
Kshitij-Katiyar marked this conversation as resolved.
Show resolved Hide resolved

var response []*autolink.Autolink
Kshitij-Katiyar marked this conversation as resolved.
Show resolved Hide resolved
if err = json.Unmarshal(respBody, &response); err != nil {
return nil, err
}

return response, nil
}

func (c *Client) call(url, method string, body []byte, queryParams url.Values) (*http.Response, error) {
req, err := http.NewRequest(method, url, bytes.NewReader(body))
if err != nil {
return nil, err
}

req.URL.RawQuery = queryParams.Encode()

resp, err := c.Do(req)
if err != nil {
return nil, err
}

return resp, nil
}