357 lines
8.0 KiB
Go
357 lines
8.0 KiB
Go
package azure
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/json"
|
|
"errors"
|
|
"fmt"
|
|
"io"
|
|
"net/http"
|
|
"net/url"
|
|
"os"
|
|
"path"
|
|
"time"
|
|
)
|
|
|
|
type Graph struct {
|
|
*accessToken
|
|
tenantId string
|
|
groupId string
|
|
}
|
|
|
|
func NewGraphByEnv() *Graph {
|
|
tenantId := os.Getenv("GRAPH_TENANT_ID")
|
|
groupId := os.Getenv("GRAPH_GROUP_ID")
|
|
return NewGraph(tenantId, groupId)
|
|
}
|
|
|
|
func NewGraph(tenantId string, groupId string) *Graph {
|
|
return &Graph{
|
|
accessToken: &accessToken{
|
|
url: fmt.Sprintf("https://login.microsoftonline.com/%s/oauth2/v2.0/token", tenantId),
|
|
values: url.Values{
|
|
"grant_type": {"client_credentials"},
|
|
"client_id": {microsoftAppId()},
|
|
"scope": {"https://graph.microsoft.com/.default"},
|
|
"client_secret": {microsoftAppPassword()},
|
|
},
|
|
},
|
|
tenantId: tenantId,
|
|
groupId: groupId,
|
|
}
|
|
}
|
|
|
|
func (s Graph) GroupId() string {
|
|
return s.groupId
|
|
}
|
|
|
|
var errGroupIdMissing = errors.New("GRAPH_GROUP_ID is missing")
|
|
|
|
func (s Graph) ReadFile(relativePath string) (io.ReadCloser, error) {
|
|
if len(s.groupId) == 0 {
|
|
return nil, errGroupIdMissing
|
|
}
|
|
|
|
token, err := s.getAuthoizationToken()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
requrl := fmt.Sprintf("https://graph.microsoft.com/v1.0/groups/%s/drive/root:/%s:/content", s.groupId, relativePath)
|
|
req, _ := http.NewRequest("GET", requrl, nil)
|
|
|
|
req.Header.Add("Authorization", token)
|
|
resp, err := http.DefaultClient.Do(req)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if resp.StatusCode != http.StatusOK {
|
|
resp.Body.Close()
|
|
return nil, errors.New(resp.Status)
|
|
}
|
|
|
|
return resp.Body, nil
|
|
}
|
|
|
|
func (s Graph) GetWebURLOfFile(relativePath string) (string, error) {
|
|
if len(s.groupId) == 0 {
|
|
return "", errGroupIdMissing
|
|
}
|
|
|
|
token, err := s.getAuthoizationToken()
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
requrl := fmt.Sprintf("https://graph.microsoft.com/v1.0/groups/%s/drive/root:/%s:", s.groupId, relativePath)
|
|
req, _ := http.NewRequest("GET", requrl, nil)
|
|
|
|
req.Header.Add("Authorization", token)
|
|
resp, err := http.DefaultClient.Do(req)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
defer func() {
|
|
io.Copy(io.Discard, resp.Body)
|
|
resp.Body.Close()
|
|
}()
|
|
|
|
itemdoc, _ := io.ReadAll(resp.Body)
|
|
var item map[string]interface{}
|
|
json.Unmarshal(itemdoc, &item)
|
|
|
|
url, ok := item["webUrl"]
|
|
if ok {
|
|
return url.(string), nil
|
|
}
|
|
|
|
return "", nil
|
|
}
|
|
|
|
func (s Graph) DownloadFile(relativePath string, outputFile string) error {
|
|
body, err := s.ReadFile(relativePath)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer body.Close()
|
|
|
|
// Create the file
|
|
out, err := os.Create(outputFile)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer out.Close()
|
|
|
|
// Write the body to file
|
|
_, err = io.Copy(out, body)
|
|
return err
|
|
}
|
|
|
|
func (s Graph) UploadStream(relativePath string, reader io.Reader) (string, error) {
|
|
if len(s.groupId) == 0 {
|
|
return "", errGroupIdMissing
|
|
}
|
|
|
|
token, err := s.getAuthoizationToken()
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
requrl := fmt.Sprintf("https://graph.microsoft.com/v1.0/groups/%s/drive/root:/%s:/content", s.groupId, relativePath)
|
|
req, _ := http.NewRequest("PUT", requrl, reader)
|
|
|
|
req.Header.Add("Authorization", token)
|
|
req.Header.Add("Content-Type", "text/plain")
|
|
|
|
resp, err := http.DefaultClient.Do(req)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
defer func() {
|
|
io.Copy(io.Discard, resp.Body)
|
|
resp.Body.Close()
|
|
}()
|
|
|
|
body, _ := io.ReadAll(resp.Body)
|
|
unquot, _ := unescapeUnicodeCharactersInJSON(body)
|
|
|
|
var drive map[string]interface{}
|
|
err = json.Unmarshal([]byte(unquot), &drive)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
if errnode, ok := drive["error"]; ok {
|
|
errmsg := errnode.(map[string]interface{})["message"].(string)
|
|
return "", errors.New(errmsg)
|
|
}
|
|
|
|
return drive["webUrl"].(string), nil
|
|
}
|
|
|
|
func (s Graph) UploadBytes(relativePath string, content []byte) (string, error) {
|
|
return s.UploadStream(relativePath, bytes.NewReader(content))
|
|
}
|
|
|
|
func (s Graph) GetChannelFilesFolderName(channel string) (string, error) {
|
|
if len(s.groupId) == 0 {
|
|
return "", errGroupIdMissing
|
|
}
|
|
|
|
token, err := s.getAuthoizationToken()
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
requrl := fmt.Sprintf("https://graph.microsoft.com/v1.0/teams/%s/channels/%s/filesFolder", s.groupId, channel)
|
|
req, _ := http.NewRequest("GET", requrl, nil)
|
|
req.Header.Add("Authorization", token)
|
|
req.Header.Add("Accept", "application/json")
|
|
|
|
resp, err := http.DefaultClient.Do(req)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
defer func() {
|
|
io.Copy(io.Discard, resp.Body)
|
|
resp.Body.Close()
|
|
}()
|
|
body, _ := io.ReadAll(resp.Body)
|
|
|
|
unquot, _ := unescapeUnicodeCharactersInJSON(body)
|
|
|
|
var drive map[string]interface{}
|
|
err = json.Unmarshal([]byte(unquot), &drive)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
if errnode, ok := drive["error"]; ok {
|
|
errmsg := errnode.(map[string]interface{})["message"].(string)
|
|
return "", errors.New(errmsg)
|
|
}
|
|
|
|
return drive["name"].(string), nil
|
|
}
|
|
|
|
func (s Graph) listChildren(path string) (map[string]interface{}, error) {
|
|
if len(s.groupId) == 0 {
|
|
return nil, errGroupIdMissing
|
|
}
|
|
|
|
token, err := s.getAuthoizationToken()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// groupId := "612620b7-cd90-4b3f-a9bd-d34cddf52517"
|
|
var requrl string
|
|
if len(path) == 0 {
|
|
requrl = fmt.Sprintf("https://graph.microsoft.com/v1.0/groups/%s/drive/root/children", s.groupId)
|
|
} else {
|
|
requrl = fmt.Sprintf("https://graph.microsoft.com/v1.0/groups/%s/drive/root:/%s:/children", s.groupId, path)
|
|
}
|
|
req, _ := http.NewRequest("GET", requrl, nil)
|
|
req.Header.Add("Authorization", token)
|
|
req.Header.Add("Accept", "application/json")
|
|
resp, err := http.DefaultClient.Do(req)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
defer func() {
|
|
io.Copy(io.Discard, resp.Body)
|
|
resp.Body.Close()
|
|
}()
|
|
body, _ := io.ReadAll(resp.Body)
|
|
|
|
unquot, _ := unescapeUnicodeCharactersInJSON(body)
|
|
|
|
var drive map[string]interface{}
|
|
err = json.Unmarshal([]byte(unquot), &drive)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if errnode, ok := drive["error"]; ok {
|
|
errmsg := errnode.(map[string]interface{})["message"].(string)
|
|
return nil, errors.New(errmsg)
|
|
}
|
|
|
|
return drive, nil
|
|
}
|
|
|
|
func (s Graph) ListFolders(parent string) ([]string, error) {
|
|
drive, err := s.listChildren(parent)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
var output []string
|
|
items := drive["value"].([]interface{})
|
|
for _, item := range items {
|
|
itemobj := item.(map[string]interface{})
|
|
if _, ok := itemobj["file"]; !ok {
|
|
output = append(output, itemobj["name"].(string))
|
|
}
|
|
}
|
|
return output, nil
|
|
}
|
|
|
|
type FileMeta struct {
|
|
Path string `json:"path"`
|
|
LastModified time.Time `json:"lastModified"`
|
|
}
|
|
|
|
func (s Graph) ListFiles(parent string) ([]FileMeta, error) {
|
|
drive, err := s.listChildren(parent)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
var output []FileMeta
|
|
items := drive["value"].([]interface{})
|
|
for _, item := range items {
|
|
itemobj := item.(map[string]interface{})
|
|
if _, ok := itemobj["file"]; ok {
|
|
modTime, _ := time.Parse(time.RFC3339, itemobj["lastModifiedDateTime"].(string))
|
|
|
|
output = append(output, FileMeta{
|
|
Path: path.Join(parent, itemobj["name"].(string)),
|
|
LastModified: modTime,
|
|
})
|
|
}
|
|
}
|
|
return output, nil
|
|
}
|
|
|
|
func (s Graph) GetChannels() (map[string]string, error) {
|
|
if len(s.groupId) == 0 {
|
|
return nil, errGroupIdMissing
|
|
}
|
|
|
|
token, err := s.getAuthoizationToken()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
requrl := fmt.Sprintf("https://graph.microsoft.com/v1.0/teams/%s/channels", s.groupId)
|
|
req, _ := http.NewRequest("GET", requrl, nil)
|
|
req.Header.Add("Authorization", token)
|
|
resp, err := http.DefaultClient.Do(req)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer func() {
|
|
io.Copy(io.Discard, resp.Body)
|
|
resp.Body.Close()
|
|
}()
|
|
body, err := io.ReadAll(resp.Body)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
var raw map[string]interface{}
|
|
if err = json.Unmarshal(body, &raw); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if errnode, ok := raw["error"]; ok {
|
|
return nil, errors.New(errnode.(map[string]interface{})["message"].(string))
|
|
}
|
|
|
|
if r, ok := raw["value"]; ok {
|
|
valuenode := r.([]interface{})
|
|
output := make(map[string]string)
|
|
for _, v := range valuenode {
|
|
data := v.(map[string]interface{})
|
|
id := data["id"].(string)
|
|
displayname := data["displayName"].(string)
|
|
output[id] = displayname
|
|
}
|
|
return output, nil
|
|
}
|
|
|
|
return nil, errors.New("error")
|
|
}
|