Skip to content

Commit

Permalink
Enable creating documents as logged-in user (take 2) (#526)
Browse files Browse the repository at this point in the history
* Add temporary drafts folder config

* Enable creating documents as logged-in user (take 2)
  • Loading branch information
jfreda authored Dec 21, 2023
1 parent ceb1bb3 commit 83ed46f
Show file tree
Hide file tree
Showing 5 changed files with 145 additions and 38 deletions.
6 changes: 6 additions & 0 deletions configs/config.hcl
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,12 @@ google_workspace {
// {shortcut_folder}/{doc_type}/{product}/{document}
shortcuts_folder = "my-shortcuts-folder-id"

// temporary_drafts_folder is a folder that will brieflly contain document
// drafts before they are moved to the drafts_folder. This is used when
// create_docs_as_user is true in the auth block, so document notification
// settings will be the same as when a user creates their own document.
// temporary_drafts_folder = "my-temporary-drafts-folder-id"

// auth is the configuration for interacting with Google Workspace using a
// service account.
// auth {
Expand Down
78 changes: 62 additions & 16 deletions internal/api/drafts.go
Original file line number Diff line number Diff line change
Expand Up @@ -127,12 +127,16 @@ func DraftsHandler(
}
title := fmt.Sprintf("[%s-???] %s", req.ProductAbbreviation, req.Title)

// If configured to create documents as the logged-in Hermes user, create
// a new Google Drive service to do this.
copyTemplateSvc := *s
var (
err error
f *drive.File
)

// Copy template to new draft file.
if cfg.GoogleWorkspace.Auth != nil &&
cfg.GoogleWorkspace.Auth.CreateDocsAsUser {

// If configured to create documents as the logged-in Hermes user,
// create a new Google Drive service to do this.
ctx := context.Background()
conf := &jwt.Config{
Email: cfg.GoogleWorkspace.Auth.ClientEmail,
Expand All @@ -144,8 +148,7 @@ func DraftsHandler(
TokenURL: cfg.GoogleWorkspace.Auth.TokenURL,
}
client := conf.Client(ctx)

var err error
copyTemplateSvc := *s
copyTemplateSvc.Drive, err = drive.NewService(
ctx, option.WithHTTPClient(client))
if err != nil {
Expand All @@ -158,17 +161,60 @@ func DraftsHandler(
w, "Error processing request", http.StatusInternalServerError)
return
}
}

// Copy template to new draft file.
f, err := copyTemplateSvc.CopyFile(
template, title, cfg.GoogleWorkspace.DraftsFolder)
if err != nil {
l.Error("error creating draft", "error", err, "template", template,
"drafts_folder", cfg.GoogleWorkspace.DraftsFolder)
http.Error(w, "Error creating document draft",
http.StatusInternalServerError)
return
// Copy template as user to new draft file in temporary drafts folder.
f, err = copyTemplateSvc.CopyFile(
template, title, cfg.GoogleWorkspace.TemporaryDraftsFolder)
if err != nil {
l.Error(
"error copying template as user to temporary drafts folder",
"error", err,
"method", r.Method,
"path", r.URL.Path,
"template", template,
"drafts_folder", cfg.GoogleWorkspace.DraftsFolder,
"temporary_drafts_folder", cfg.GoogleWorkspace.
TemporaryDraftsFolder,
)
http.Error(w, "Error creating document draft",
http.StatusInternalServerError)
return
}

// Move draft file to drafts folder using service user.
_, err = s.MoveFile(
f.Id, cfg.GoogleWorkspace.DraftsFolder)
if err != nil {
l.Error(
"error moving draft file to drafts folder",
"error", err,
"method", r.Method,
"path", r.URL.Path,
"doc_id", f.Id,
"drafts_folder", cfg.GoogleWorkspace.DraftsFolder,
"temporary_drafts_folder", cfg.GoogleWorkspace.
TemporaryDraftsFolder,
)
http.Error(w, "Error creating document draft",
http.StatusInternalServerError)
return
}
} else {
// Copy template to new draft file as service user.
f, err = s.CopyFile(
template, title, cfg.GoogleWorkspace.DraftsFolder)
if err != nil {
l.Error("error creating draft",
"error", err,
"method", r.Method,
"path", r.URL.Path,
"template", template,
"drafts_folder", cfg.GoogleWorkspace.DraftsFolder,
)
http.Error(w, "Error creating document draft",
http.StatusInternalServerError)
return
}
}

// Build created date.
Expand Down
83 changes: 62 additions & 21 deletions internal/api/v2/drafts.go
Original file line number Diff line number Diff line change
Expand Up @@ -122,12 +122,16 @@ func DraftsHandler(srv server.Server) http.Handler {
}
title := fmt.Sprintf("[%s-???] %s", req.ProductAbbreviation, req.Title)

// If configured to create documents as the logged-in Hermes user, create
// a new Google Drive service to do this.
copyTemplateSvc := *srv.GWService
var (
err error
f *drive.File
)

// Copy template to new draft file.
if srv.Config.GoogleWorkspace.Auth != nil &&
srv.Config.GoogleWorkspace.Auth.CreateDocsAsUser {

// If configured to create documents as the logged-in Hermes user,
// create a new Google Drive service to do this.
ctx := context.Background()
conf := &jwt.Config{
Email: srv.Config.GoogleWorkspace.Auth.ClientEmail,
Expand All @@ -139,8 +143,7 @@ func DraftsHandler(srv server.Server) http.Handler {
TokenURL: srv.Config.GoogleWorkspace.Auth.TokenURL,
}
client := conf.Client(ctx)

var err error
copyTemplateSvc := *srv.GWService
copyTemplateSvc.Drive, err = drive.NewService(
ctx, option.WithHTTPClient(client))
if err != nil {
Expand All @@ -153,22 +156,60 @@ func DraftsHandler(srv server.Server) http.Handler {
w, "Error processing request", http.StatusInternalServerError)
return
}
}

// Copy template to new draft file.
f, err := copyTemplateSvc.CopyFile(
template, title, srv.Config.GoogleWorkspace.DraftsFolder)
if err != nil {
srv.Logger.Error("error creating draft",
"error", err,
"method", r.Method,
"path", r.URL.Path,
"template", template,
"drafts_folder", srv.Config.GoogleWorkspace.DraftsFolder,
)
http.Error(w, "Error creating document draft",
http.StatusInternalServerError)
return
// Copy template as user to new draft file in temporary drafts folder.
f, err = copyTemplateSvc.CopyFile(
template, title, srv.Config.GoogleWorkspace.TemporaryDraftsFolder)
if err != nil {
srv.Logger.Error(
"error copying template as user to temporary drafts folder",
"error", err,
"method", r.Method,
"path", r.URL.Path,
"template", template,
"drafts_folder", srv.Config.GoogleWorkspace.DraftsFolder,
"temporary_drafts_folder", srv.Config.GoogleWorkspace.
TemporaryDraftsFolder,
)
http.Error(w, "Error creating document draft",
http.StatusInternalServerError)
return
}

// Move draft file to drafts folder using service user.
_, err = srv.GWService.MoveFile(
f.Id, srv.Config.GoogleWorkspace.DraftsFolder)
if err != nil {
srv.Logger.Error(
"error moving draft file to drafts folder",
"error", err,
"method", r.Method,
"path", r.URL.Path,
"doc_id", f.Id,
"drafts_folder", srv.Config.GoogleWorkspace.DraftsFolder,
"temporary_drafts_folder", srv.Config.GoogleWorkspace.
TemporaryDraftsFolder,
)
http.Error(w, "Error creating document draft",
http.StatusInternalServerError)
return
}
} else {
// Copy template to new draft file as service user.
f, err = srv.GWService.CopyFile(
template, title, srv.Config.GoogleWorkspace.DraftsFolder)
if err != nil {
srv.Logger.Error("error creating draft",
"error", err,
"method", r.Method,
"path", r.URL.Path,
"template", template,
"drafts_folder", srv.Config.GoogleWorkspace.DraftsFolder,
)
http.Error(w, "Error creating document draft",
http.StatusInternalServerError)
return
}
}

// Build created date.
Expand Down
10 changes: 9 additions & 1 deletion internal/cmd/commands/server/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -220,8 +220,16 @@ func (c *Command) Run(args []string) int {

// Initialize Google Workspace service.
var goog *gw.Service
// Use Google Workspace service user auth if it is defined in the config.
if cfg.GoogleWorkspace.Auth != nil {
// Use Google Workspace auth if it is defined in the config.
// Validate temporary drafts folder is configured if creating docs as user.
if cfg.GoogleWorkspace.Auth.CreateDocsAsUser &&
cfg.GoogleWorkspace.TemporaryDraftsFolder == "" {
c.UI.Error(
"error initializing server: Google Workspace temporary drafts folder is required if create_docs_as_user is true")
return 1
}

goog = gw.NewFromConfig(cfg.GoogleWorkspace.Auth)
} else {
// Use OAuth if Google Workspace auth is not defined in the config.
Expand Down
6 changes: 6 additions & 0 deletions internal/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,12 @@ type GoogleWorkspace struct {
// ShortcutsFolder is the folder that contains document shortcuts organized
// into doc type and product subfolders.
ShortcutsFolder string `hcl:"shortcuts_folder"`

// TemporaryDraftsFolder is a folder that will brieflly contain document
// drafts before they are moved to the DraftsFolder. This is used when
// create_docs_as_user is true in the auth block, so document notification
// settings will be the same as when a user creates their own document.
TemporaryDraftsFolder string `hcl:"temporary_drafts_folder,optional"`
}

// GoogleWorkspaceOAuth2 is the configuration to use OAuth 2.0 to access Google
Expand Down

0 comments on commit 83ed46f

Please sign in to comment.