520 lines
13 KiB
Go
520 lines
13 KiB
Go
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)
|
||
}
|