docxTemplater/handlers/gdisk.go

520 lines
13 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package handlers
import (
"errors"
"fmt"
"io"
"net/http"
"os"
"github.com/gorilla/schema"
"go.uber.org/zap"
"google.golang.org/api/drive/v3"
"penahub.gitlab.yandexcloud.net/backend/templategen/dal/model"
GDisk "penahub.gitlab.yandexcloud.net/backend/templategen/gdisk"
"penahub.gitlab.yandexcloud.net/backend/templategen/middleware"
"penahub.gitlab.yandexcloud.net/backend/templategen/templategen"
"penahub.gitlab.yandexcloud.net/backend/templategen/tools"
)
type ReqGDiskSaveToken struct {
State string `json:"state" schema:"state"`
Code string `json:"code" schema:"code"`
Scope string `json:"scope" schema:"scope"`
}
// GDiskSaveToken - сохраняет токен авторизации.
func (h *Handlers) GDiskSaveToken(w http.ResponseWriter, r *http.Request) {
var request ReqGDiskSaveToken
err := r.ParseForm()
if err != nil {
h.reportError(w, http.StatusBadRequest, err)
return
}
err = schema.NewDecoder().Decode(&request, r.Form)
if err != nil {
h.reportError(w, 500, err)
return
}
if request.State == "" {
err = errors.New("GDiskErr: got empty state")
h.reportError(w, http.StatusBadRequest, err)
return
}
if request.Code == "" {
err = errors.New("GDiskErr: got empty code")
h.reportError(w, http.StatusBadRequest, err)
return
}
// get user
var state tools.StateToken
err = tools.DecryptTokenAES(request.State, &state)
if err != nil {
h.reportError(w, http.StatusUnauthorized, err)
return
}
// generate token
token, err := h.GDisk.GetToken(r.Context(), request.Code)
if err != nil {
h.reportError(w, http.StatusInternalServerError, err)
return
}
gDisk, err := h.GDisk.NewClient(r.Context(), token)
if err != nil {
h.reportError(w, http.StatusInternalServerError, err)
return
}
token = gDisk.Token
gUser, err := gDisk.GetUserInfo(r.Context())
if err != nil {
h.reportError(w, http.StatusInternalServerError, err)
return
}
// Make default directories in Google Drive
gDiskData, err := h.dal.GDisk.GetByEmail(r.Context(), gUser.EmailAddress)
if err != nil {
h.reportError(w, http.StatusInternalServerError, err)
return
}
var defaultID, defaultName, templateID, templateName, saveID, saveName string
if gDiskData != nil {
defaultID = gDiskData.DefaultFolderID
defaultName = gDiskData.DefaultFolder
templateID = gDiskData.TemplateFolderID
templateName = gDiskData.TemplateFolder
saveID = gDiskData.SaveFolderID
saveName = gDiskData.SaveFolder
}
defaultFolder, templateFolder, saveFolder, err := gDisk.MakeDefaultDirs(defaultID, defaultName, templateID,
templateName, saveID, saveName)
if err != nil {
h.reportError(w, http.StatusInternalServerError, err)
return
}
// Insert/Update token in DB
_, err = h.dal.GDisk.InsertOrUpdate(r.Context(), &model.GDisk{
PenaID: state.PenaID,
Name: fmt.Sprintf("Google Disk (%v)", gUser.EmailAddress),
DisplayName: gUser.DisplayName,
Email: gUser.EmailAddress,
PhotoLink: gUser.PhotoLink,
AccessToken: token.AccessToken,
RefreshToken: token.RefreshToken,
ExpiresIn: token.Expiry,
TokenType: token.TokenType,
DefaultFolder: defaultFolder.Name,
DefaultFolderID: defaultFolder.Id,
TemplateFolder: templateFolder.Name,
TemplateFolderID: templateFolder.Id,
SaveFolder: saveFolder.Name,
SaveFolderID: saveFolder.Id,
})
if err != nil {
h.reportError(w, http.StatusInternalServerError, err)
return
}
http.Redirect(w, r, state.RedirectURL, http.StatusPermanentRedirect)
}
type ReqGDiskSetSettings struct {
ID string `json:"id"`
Name string `json:"name"` // Пользовательское название хранилища
DefaultFolder string `json:"default_folder"`
DefaultFolderID string `json:"default_folder_id"`
TemplateFolder string `json:"template_folder"`
TemplateFolderID string `json:"template_folder_id"`
SaveFolder string `json:"save_folder"`
SaveFolderID string `json:"save_folder_id"`
}
func (h *Handlers) GDiskSetSettings(w http.ResponseWriter, r *http.Request) {
var request ReqGDiskSetSettings
amoData := middleware.GetAmoData(r)
if amoData == nil {
h.reportError(w, http.StatusUnauthorized, ErrorUnauthorized)
return
}
err := decodePost(&request, r)
if err != nil {
h.reportError(w, http.StatusBadRequest, err)
return
}
if request.ID == "" {
h.reportError(w, http.StatusBadRequest, errors.New("id required"))
return
}
err = h.dal.GDisk.Update(r.Context(), &model.GDisk{
ID: request.ID,
Name: request.Name,
DefaultFolder: request.DefaultFolder,
DefaultFolderID: request.DefaultFolderID,
TemplateFolder: request.TemplateFolder,
TemplateFolderID: request.TemplateFolderID,
SaveFolder: request.SaveFolder,
SaveFolderID: request.SaveFolderID,
})
if err != nil {
h.reportError(w, http.StatusInternalServerError, err)
return
}
w.WriteHeader(http.StatusOK)
}
type ReqGDiskGetResources struct {
ID string `json:"id"` // ID хранилища
FolderID string `json:"folder_id"` // Folder id
Name string `json:"name,omitempty"` // Folder name
ParentID string `json:"parent_id,omitempty"` // Parent folder id
}
// GDiskGetResources - возвращает поиск по папке, включая список её файлов и папок.
// Поведение:
// - Если не указан FolderID и Name возвращает корневой каталог Google Drive
// - Если указан только Name ищет файл\папку по всему Google Drive
// - Если указан Name и ParentID ищет файл\папку только в родителе
// - ParentID игнорируется без Name
func (h *Handlers) GDiskGetResources(w http.ResponseWriter, r *http.Request) {
var request ReqGDiskGetResources
amoData := middleware.GetAmoData(r)
if amoData == nil {
h.reportError(w, http.StatusUnauthorized, ErrorUnauthorized)
return
}
err := decodePost(&request, r)
if err != nil {
h.reportError(w, http.StatusBadRequest, err)
return
}
if request.ID == "" {
h.reportError(w, http.StatusBadRequest, errors.New("id required"))
return
}
gdiskInfo, err := h.dal.GDisk.GetByID(r.Context(), request.ID)
if err != nil {
h.reportError(w, http.StatusInternalServerError, err)
return
}
if gdiskInfo == nil {
h.reportError(w, http.StatusForbidden, errors.New("gdisk info not found"))
return
}
client, err := h.GDisk.NewClient(r.Context(), gdiskInfo.Token())
if err != nil {
h.reportError(w, http.StatusForbidden, err)
return
}
var res *drive.FileList
if request.Name != "" {
res, err = client.GetResourcesByName(request.Name, request.ParentID)
} else {
res, err = client.GetResources(request.FolderID)
}
if err != nil {
h.reportError(w, http.StatusInternalServerError, err)
return
}
h.sendResponse(w, http.StatusOK, res)
}
type ReqGDiskGetDirTemplate struct {
Email string `json:"email"` // Required. Google Email ?
}
// GDiskGetDirTemplate - возвращает данные по папке template, включая список её файлов и папок.
func (h *Handlers) GDiskGetDirTemplate(w http.ResponseWriter, r *http.Request) {
var request ReqGDiskGetDirTemplate
err := decodePost(&request, r)
if err != nil {
h.reportError(w, http.StatusBadRequest, err)
return
}
if request.Email == "" {
h.reportError(w, http.StatusBadRequest, errors.New("email required"))
}
amoData := middleware.GetAmoData(r)
if amoData == nil {
h.reportError(w, http.StatusUnauthorized, ErrorUnauthorized)
return
}
gdiskInfo, err := h.dal.GDisk.GetByEmail(r.Context(), request.Email)
if err != nil {
h.reportError(w, http.StatusInternalServerError, err)
return
}
if gdiskInfo == nil {
h.reportError(w, http.StatusForbidden, errors.New("gdisk info not found"))
return
}
if gdiskInfo.Token() == nil {
h.reportError(w, http.StatusForbidden, errors.New("google token invalid"))
return
}
client, err := h.GDisk.NewClient(r.Context(), gdiskInfo.Token())
if err != nil {
h.reportError(w, http.StatusInternalServerError, err)
return
}
dir, err := client.GetResources(gdiskInfo.TemplateFolderID)
if err != nil {
h.reportError(w, http.StatusInternalServerError, err)
return
}
h.sendResponse(w, http.StatusOK, dir)
}
// GDiskGetList - возвращает список хранилищ Google закрепленных за пользователем по его UserID из JWT.
func (h *Handlers) GDiskGetList(w http.ResponseWriter, r *http.Request) {
amoData := middleware.GetAmoData(r)
if amoData == nil {
h.reportError(w, http.StatusUnauthorized, ErrorUnauthorized)
return
}
gdiskInfo, err := h.dal.GDisk.GetListByPenaID(r.Context(), amoData.PenaID)
if err != nil {
h.reportError(w, http.StatusInternalServerError, err)
return
}
h.sendResponse(w, http.StatusOK, gdiskInfo)
}
type ReqGDiskPutResources struct {
ID string `json:"ID"`
Name string `json:"name"`
ParentID string `json:"parent_id"`
}
// GDiskPutResources - создать папку в хранилище.
func (h *Handlers) GDiskPutResources(w http.ResponseWriter, r *http.Request) {
var request ReqGDiskPutResources
amoData := middleware.GetAmoData(r)
if amoData == nil {
h.reportError(w, http.StatusUnauthorized, ErrorUnauthorized)
return
}
err := decodePost(&request, r)
if err != nil {
h.reportError(w, http.StatusBadRequest, err)
return
}
if request.ID == "" {
h.reportError(w, http.StatusBadRequest, errors.New("id required"))
return
}
if request.Name == "" {
h.reportError(w, http.StatusBadRequest, errors.New("name required"))
return
}
gdiskInfo, err := h.dal.GDisk.GetByID(r.Context(), request.ID)
if err != nil {
h.reportError(w, http.StatusInternalServerError, err)
return
}
if gdiskInfo == nil {
h.reportError(w, http.StatusForbidden, errors.New("gdisk info not found"))
return
}
client, err := h.GDisk.NewClient(r.Context(), gdiskInfo.Token())
if err != nil {
h.reportError(w, http.StatusForbidden, err)
return
}
file, err := client.PutResources(request.Name, request.ParentID)
if err != nil {
h.reportError(w, http.StatusInternalServerError, err)
return
}
h.sendResponse(w, http.StatusOK, file)
}
type ReqGDiskUploadResources struct {
ID string `json:"id" schema:"id"` // Storage ID
ParentID string `json:"parent_id" schema:"parent_id"`
}
// GDiskUploadResources - загрузить файл в хранилище.
func (h *Handlers) GDiskUploadResources(w http.ResponseWriter, r *http.Request) {
// Check form
fileData, fileHeader, err := r.FormFile("file")
defer fileData.Close() //nolint
if err != nil {
h.reportError(w, http.StatusInternalServerError, err)
return
}
var req ReqGDiskUploadResources
err = schema.NewDecoder().Decode(&req, r.Form)
if err != nil {
h.reportError(w, http.StatusBadRequest, err)
return
}
if req.ID == "" {
h.reportError(w, http.StatusBadRequest, errors.New("id required"))
return
}
var maxSize int64 = 10 << 20 // mb
if fileHeader.Size > maxSize {
h.reportError(w, http.StatusBadRequest, errors.New("max size 10 mb"))
return
}
// Download file to the temp
downloadPath := fmt.Sprintf("%v/%v", templategen.TempDownloaded, fileHeader.Filename)
out, err := os.Create(downloadPath)
defer out.Close() //nolint
if err != nil {
h.reportError(w, http.StatusInternalServerError, err)
return
}
_, err = io.Copy(out, fileData)
if err != nil {
h.reportError(w, http.StatusInternalServerError, err)
return
}
// Upload file to the storage
storage, err := h.dal.GDisk.GetByID(r.Context(), req.ID)
if err != nil {
h.reportError(w, http.StatusInternalServerError, err)
return
}
client, err := h.GDisk.NewClient(r.Context(), storage.Token())
if err != nil {
h.reportError(w, http.StatusInternalServerError, err)
return
}
h.logger.Info("INFO", zap.String("downloadPath", downloadPath))
_, _, err = client.UploadFile(downloadPath, GDisk.MimeTypeDocx, req.ParentID)
if err != nil {
h.reportError(w, http.StatusInternalServerError, err)
return
}
w.WriteHeader(http.StatusOK)
}
type ReqGDiskDeleteResources struct {
ID string `json:"id"`
FolderID string `json:"folder_id"`
}
// GDiskDeleteResources - удалить папку\файл.
func (h *Handlers) GDiskDeleteResources(w http.ResponseWriter, r *http.Request) {
var request ReqGDiskDeleteResources
amoData := middleware.GetAmoData(r)
if amoData == nil {
h.reportError(w, http.StatusUnauthorized, ErrorUnauthorized)
return
}
err := decodePost(&request, r)
if err != nil {
h.reportError(w, http.StatusBadRequest, err)
return
}
if request.ID == "" {
h.reportError(w, http.StatusBadRequest, errors.New("id required"))
return
}
if request.FolderID == "" {
h.reportError(w, http.StatusBadRequest, errors.New("folder_id required"))
return
}
gdiskInfo, err := h.dal.GDisk.GetByID(r.Context(), request.ID)
if err != nil {
h.reportError(w, http.StatusInternalServerError, err)
return
}
if gdiskInfo == nil {
h.reportError(w, http.StatusForbidden, errors.New("gdisk info not found"))
return
}
client, err := h.GDisk.NewClient(r.Context(), gdiskInfo.Token())
if err != nil {
h.reportError(w, http.StatusForbidden, err)
return
}
err = client.DeleteResources(request.FolderID)
if err != nil {
h.reportError(w, http.StatusInternalServerError, err)
return
}
w.WriteHeader(http.StatusOK)
}