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

Added the feature to create pages from mm for both cloud and server #20

Open
wants to merge 4 commits into
base: auth/notification
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions server/client.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package main

import "github.com/mattermost/mattermost-plugin-confluence/server/serializer"

// Client is the combined interface for all upstream APIs and convenience methods.
type Client interface {
RESTService
Expand All @@ -13,4 +15,6 @@ type RESTService interface {
GetSpaceData(string) (*SpaceResponse, error)
GetUserGroups(*Connection) ([]*UserGroup, error)
GetPageData(pageID int) (*PageResponse, error)
GetSpacesForConfluenceURL() ([]*SpaceForConfluenceURL, error)
CreatePage(string, *serializer.PageDetails) (*CreatePageResponse, error)
}
45 changes: 44 additions & 1 deletion server/client_cloud.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@ import (

const (
PathAccessibleResources = "/oauth/token/accessible-resources"
PathGetUserGroupsForCloud = "rest/api/user/memberof?accountId=%s"
PathGetUserGroupsForCloud = "/rest/api/user/memberof?accountId=%s"
PathGetSpacesForCloud = "/rest/api/space?limit=100"
PathCreatePageForCloud = "/rest/api/content"
)

type confluenceCloudClient struct {
Expand Down Expand Up @@ -157,3 +159,44 @@ func (ccc *confluenceCloudClient) GetUserGroups(connection *Connection) ([]*User

return userGroups.Groups, nil
}

func (ccc *confluenceCloudClient) GetSpacesForConfluenceURL() ([]*SpaceForConfluenceURL, error) {
spacesForConfluenceURL := SpacesForConfluenceURL{}
url, err := utils.GetEndpointURL(ccc.URL, PathGetSpacesForCloud)

if err != nil {
return nil, errors.Wrap(err, "confluence GetSpacesForConfluenceURL")
}
_, err = utils.CallJSON(ccc.URL, http.MethodGet, url, nil, &spacesForConfluenceURL, ccc.HTTPClient)
if err != nil {
return nil, errors.Wrap(err, "confluence GetSpacesForConfluenceURL")
}
return spacesForConfluenceURL.Spaces, nil
}

func (ccc *confluenceCloudClient) CreatePage(spaceKey string, pageDetails *serializer.PageDetails) (*CreatePageResponse, error) {
requestBody := &CreatePageRequestBody{
Title: pageDetails.Title,
Type: "page",
Space: SpaceForPageCreate{
Key: spaceKey,
},
Body: BodyForPageCreate{
Storage: Storage{
Value: pageDetails.Description,
Representation: "storage",
},
},
}

createPageResponse := &CreatePageResponse{}
url, err := utils.GetEndpointURL(ccc.URL, PathCreatePageForCloud)
if err != nil {
return nil, errors.Wrap(err, "confluence CreatePage")
}
_, err = utils.CallJSON(ccc.URL, http.MethodPost, url, requestBody, createPageResponse, ccc.HTTPClient)
if err != nil {
return nil, errors.Wrap(err, "confluence CreatePage")
}
return createPageResponse, nil
}
70 changes: 70 additions & 0 deletions server/client_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ const (
PathDeleteWebhook = "/rest/api/webhooks/%s"
PathGetUserGroupsForServer = "/rest/api/user/memberof?username=%s"
PathAdminData = "/rest/api/audit/retention"
PathGetSpacesForServer = "/rest/api/space?limit=100"
PathCreatePage = "/rest/api/content"
)

const (
Expand All @@ -45,6 +47,35 @@ type CreateWebhookRequestBody struct {
Active string `json:"active"`
Configuration *WebhookConfiguration `json:"configuration"`
}
type SpaceForPageCreate struct {
Key string `json:"key"`
}

type Storage struct {
Value string `json:"value"`
Representation string `json:"representation"`
}

type BodyForPageCreate struct {
Storage Storage `json:"storage"`
}

type CreatePageRequestBody struct {
Title string `json:"title"`
Type string `json:"type"`
Space SpaceForPageCreate `json:"space"`
Body BodyForPageCreate `json:"body"`
}

type CreatePageResponse struct {
Space SpaceResponse `json:"space"`
Links LinksForPageCreate `json:"_links"`
}

type LinksForPageCreate struct {
Self string `json:"webui"`
BaseURL string `json:"base"`
}

type SpaceResponse struct {
ID int64 `json:"id"`
Expand Down Expand Up @@ -254,3 +285,42 @@ func (csc *confluenceServerClient) GetUserGroups(connection *Connection) ([]*Use

return userGroups.Groups, nil
}

func (csc *confluenceServerClient) GetSpacesForConfluenceURL() ([]*SpaceForConfluenceURL, error) {
spacesForConfluenceURL := SpacesForConfluenceURL{}
url, err := utils.GetEndpointURL(csc.URL, PathGetSpacesForServer)
if err != nil {
return nil, errors.Wrap(err, "confluence GetSpacesForConfluenceURL")
}
_, err = utils.CallJSON(csc.URL, http.MethodGet, url, nil, &spacesForConfluenceURL, csc.HTTPClient)
if err != nil {
return nil, errors.Wrap(err, "confluence GetSpacesForConfluenceURL")
}
return spacesForConfluenceURL.Spaces, nil
}

func (csc *confluenceServerClient) CreatePage(spaceKey string, pageDetails *serializer.PageDetails) (*CreatePageResponse, error) {
requestBody := &CreatePageRequestBody{
Title: pageDetails.Title,
Type: "page",
Space: SpaceForPageCreate{
Key: spaceKey,
},
Body: BodyForPageCreate{
Storage: Storage{
Value: pageDetails.Description,
Representation: "storage",
},
},
}
createPageResponse := &CreatePageResponse{}
url, err := utils.GetEndpointURL(csc.URL, PathCreatePage)
if err != nil {
return nil, errors.Wrap(err, "confluence CreatePage")
}
_, err = utils.CallJSON(csc.URL, http.MethodPost, url, requestBody, createPageResponse, csc.HTTPClient)
if err != nil {
return nil, errors.Wrap(err, "confluence CreatePage")
}
return createPageResponse, nil
}
69 changes: 69 additions & 0 deletions server/create_page.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package main

import (
"fmt"
"io/ioutil"
"net/http"

"github.com/gorilla/mux"
"github.com/mattermost/mattermost-server/v6/model"

"github.com/mattermost/mattermost-plugin-confluence/server/config"
"github.com/mattermost/mattermost-plugin-confluence/server/serializer"
"github.com/mattermost/mattermost-plugin-confluence/server/utils/types"
)

const (
pageCreateSuccess = "You created a page [%s](%s) in space [%s](%s)"
)

func (p *Plugin) handleCreatePage(w http.ResponseWriter, r *http.Request) {
params := mux.Vars(r)
spaceKey := params["spaceKey"]
channelID := params["channelID"]
userID := r.Header.Get(config.HeaderMattermostUserID)

instance, err := p.getInstanceFromURL(r.URL.Path)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}

conn, err := p.userStore.LoadConnection(types.ID(instance.GetURL()), types.ID(userID))
if err != nil {
p.LogAndRespondError(w, http.StatusInternalServerError, "error in loading connection.", err)
return
}

client, err := instance.GetClient(conn)
if err != nil {
p.LogAndRespondError(w, http.StatusInternalServerError, "not able to get Client.", err)
return
}

body, err := ioutil.ReadAll(r.Body)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}

pageDetails, err := serializer.PageDetailsFromJSON(body)
if err != nil {
p.LogAndRespondError(w, http.StatusInternalServerError, "error decoding request body for page details.", err)
return
}

createPageResponse, err := client.CreatePage(spaceKey, pageDetails)
if err != nil {
p.LogAndRespondError(w, http.StatusInternalServerError, "not able to create page.", err)
return
}

post := &model.Post{
UserId: p.conf.botUserID,
ChannelId: channelID,
Message: fmt.Sprintf(pageCreateSuccess, pageDetails.Title, fmt.Sprintf("%s%s", createPageResponse.Links.BaseURL, createPageResponse.Links.Self), spaceKey, fmt.Sprintf("%s%s", createPageResponse.Links.BaseURL, createPageResponse.Space.Links.Self)),
}
_ = p.API.SendEphemeralPost(userID, post)
ReturnStatusOK(w)
}
40 changes: 40 additions & 0 deletions server/get_spaces.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package main

import (
"encoding/json"
"net/http"

"github.com/mattermost/mattermost-plugin-confluence/server/config"
"github.com/mattermost/mattermost-plugin-confluence/server/utils/types"
)

func (p *Plugin) handleGetSpacesForConfluenceURL(w http.ResponseWriter, r *http.Request) {
userID := r.Header.Get(config.HeaderMattermostUserID)

instance, err := p.getInstanceFromURL(r.URL.Path)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}

conn, err := p.userStore.LoadConnection(types.ID(instance.GetURL()), types.ID(userID))
if err != nil {
p.LogAndRespondError(w, http.StatusInternalServerError, "error in loading connection.", err)
return
}

client, err := instance.GetClient(conn)
if err != nil {
p.LogAndRespondError(w, http.StatusInternalServerError, "not able to get Client.", err)
return
}

spaces, err := client.GetSpacesForConfluenceURL()
if err != nil {
p.LogAndRespondError(w, http.StatusInternalServerError, "not able to get Spaces for confluence url.", err)
return
}
b, _ := json.Marshal(spaces)
w.Header().Set("Content-Type", "application/json")
_, _ = w.Write([]byte(string(b)))
}
2 changes: 2 additions & 0 deletions server/http.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,8 @@ func (p *Plugin) InitAPI() *mux.Router {
apiRouter.HandleFunc(routeUserConnect, p.httpOAuth2Connect).Methods(http.MethodGet)
apiRouter.HandleFunc(routeUserComplete, p.httpOAuth2Complete).Methods(http.MethodGet)

apiRouter.HandleFunc("/spaces", p.handleGetSpacesForConfluenceURL).Methods(http.MethodGet)
apiRouter.HandleFunc("/{channelID:[A-Za-z0-9]+}/spaceKey/{spaceKey:.+}/createpage", p.handleCreatePage).Methods(http.MethodPost)
apiRouter.HandleFunc("/{channelID:[A-Za-z0-9]+}/subscription/{type:[A-Za-z_]+}", p.handleSaveSubscription).Methods(http.MethodPost)
apiRouter.HandleFunc("/{channelID:[A-Za-z0-9]+}/subscription/{type:[A-Za-z_]+}/{oldSubscriptionType:[A-Za-z_]+}", p.handleEditChannelSubscription).Methods(http.MethodPut)
apiRouter.HandleFunc("/server/webhook/{userID:.+}", p.handleConfluenceServerWebhook).Methods(http.MethodPost)
Expand Down
16 changes: 16 additions & 0 deletions server/serializer/create_page.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package serializer

import "encoding/json"

type PageDetails struct {
Title string `json:"title"`
Description string `json:"description"`
}

func PageDetailsFromJSON(body []byte) (*PageDetails, error) {
var pd PageDetails
if err := json.Unmarshal(body, &pd); err != nil {
return nil, err
}
return &pd, nil
}
9 changes: 9 additions & 0 deletions server/user.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,15 @@ type UserGroup struct {
Name string `json:"name"`
}

type SpacesForConfluenceURL struct {
Spaces []*SpaceForConfluenceURL `json:"results,omitempty"`
}

type SpaceForConfluenceURL struct {
Key string `json:"key"`
Name string `json:"name"`
}

type Connection struct {
ConfluenceUser
PluginVersion string
Expand Down
27 changes: 16 additions & 11 deletions webapp/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions webapp/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -72,9 +72,9 @@
"react-redux": "7.2.0",
"react-select": "3.1.0",
"redux": "4.0.5",
"redux-mock-store": "1.5.4",
"superagent": "5.3.1",
"typescript": "3.9.6",
"@types/react-bootstrap": "0.32.25"
"typescript": "3.9.6"
},
"jest": {
"snapshotSerializers": [
Expand Down
6 changes: 5 additions & 1 deletion webapp/src/actions/index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {
closeSubscriptionModal, openSubscriptionModal, saveChannelSubscription, editChannelSubscription, getChannelSubscription, getConnected,
closeSubscriptionModal, openSubscriptionModal, saveChannelSubscription, editChannelSubscription, getChannelSubscription, getConnected, openCreateConfluencePageModal, closeCreateConfluencePageModal, getSpacesForConfluenceURL, createPageForConfluence,
} from './subscription_modal';

export {
Expand All @@ -9,4 +9,8 @@ export {
editChannelSubscription,
getChannelSubscription,
getConnected,
openCreateConfluencePageModal,
closeCreateConfluencePageModal,
getSpacesForConfluenceURL,
createPageForConfluence,
};
Loading
Loading