Skip to content

Commit

Permalink
share implemented role and accountType + message + notification sending
Browse files Browse the repository at this point in the history
  • Loading branch information
Emmanuel Odeke committed Jan 18, 2015
1 parent 16090aa commit 619fc2d
Show file tree
Hide file tree
Showing 7 changed files with 241 additions and 28 deletions.
24 changes: 24 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
- [Pushing](#pushing)
- [Publishing](#publishing)
- [Unpublishing](#unpublishing)
- [Sharing](#sharing)
- [Unsharing](#unsharing)
- [Touching](#touch)
- [Trashing and Untrashing](#trashing-and-untrashing)
- [Emptying the Trash](#emptying-the-trash)
Expand Down Expand Up @@ -156,6 +158,28 @@ The `unpub` command is the opposite of `pub`. It unpublishes a previously publis
$ drive unpub photos
```

### Sharing

The `share` command enables you to share a set of files with specific users and assign them specific roles as well as specific generic access to the files.

```shell
$ drive share -emails [email protected],[email protected] -message "This is the substring file I told you about" -role writer -type group mnt/substringfinder.c projects/kmp.c
```

For example to share a file with users of a mailing list and a custom message

```shell
$ drive share -emails [email protected] -message "Here is the drive code" -role group mnt/drive
```

### Unsharing

The `unshare` command revokes access of a specific accountType to a set of files.

```shell
$ drive unshare -type group mnt/drive
```

### Touching

Files that exist remotely can be touched i.e their modification time updated to that on the remote server using the `touch` command:
Expand Down
57 changes: 57 additions & 0 deletions cmd/drive/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ func main() {
command.On(drive.PushKey, drive.DescPush, &pushCmd{}, []string{})
command.On(drive.PubKey, drive.DescPublish, &publishCmd{}, []string{})
command.On(drive.QuotaKey, drive.DescQuota, &quotaCmd{}, []string{})
command.On(drive.ShareKey, drive.DescShare, &shareCmd{}, []string{})
command.On(drive.UnshareKey, drive.DescUnshare, &unshareCmd{}, []string{})
command.On(drive.TouchKey, drive.DescTouch, &touchCmd{}, []string{})
command.On(drive.TrashKey, drive.DescTrash, &trashCmd{}, []string{})
command.On(drive.UntrashKey, drive.DescUntrash, &untrashCmd{}, []string{})
Expand Down Expand Up @@ -504,6 +506,61 @@ func (cmd *publishCmd) Run(args []string) {
}).Publish())
}

type unshareCmd struct {
accountType *string
}

func (cmd *unshareCmd) Flags(fs *flag.FlagSet) *flag.FlagSet {
cmd.accountType = fs.String("type", "", "scope of account to revoke access to")
return fs
}

func (cmd *unshareCmd) Run(args []string) {
sources, context, path := preprocessArgs(args)

meta := map[string][]string{
"accountType": uniqOrderedStr(nonEmptyStrings(strings.Split(*cmd.accountType, ","))),
}

exitWithError(drive.New(context, &drive.Options{
Meta: &meta,
Path: path,
Sources: sources,
}).Unshare())
}

type shareCmd struct {
emails *string
message *string
role *string
accountType *string
}

func (cmd *shareCmd) Flags(fs *flag.FlagSet) *flag.FlagSet {
cmd.emails = fs.String("emails", "", "emails to share the file to")
cmd.message = fs.String("message", "", "message to send receipients")
cmd.role = fs.String("role", "", "role to set to receipients of share")
cmd.accountType = fs.String("type", "", "scope of accounts to share files with")
return fs
}

func (cmd *shareCmd) Run(args []string) {
sources, context, path := preprocessArgs(args)

meta := map[string][]string{
"emailMessage": []string{*cmd.message},
"emails": uniqOrderedStr(nonEmptyStrings(strings.Split(*cmd.emails, ","))),
"role": uniqOrderedStr(nonEmptyStrings(strings.Split(*cmd.role, ","))),
"accountType": uniqOrderedStr(nonEmptyStrings(strings.Split(*cmd.accountType, ","))),
}

exitWithError(drive.New(context, &drive.Options{
Meta: &meta,
Path: path,
Sources: sources,
}).Share())
}

func initContext(args []string) *config.Context {
var err error
var gdPath string
Expand Down
2 changes: 1 addition & 1 deletion src/about.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import (
drive "github.com/google/google-api-go-client/drive/v2"
)

const Version = "0.0.5"
const Version = "0.0.6"

const (
Barely = iota
Expand Down
1 change: 1 addition & 0 deletions src/commands.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ type Options struct {
Hidden bool
// Allows listing of content in trash
InTrash bool
Meta *map[string][]string
Mount *config.Mount
// NoClobber when set prevents overwriting of stale content
NoClobber bool
Expand Down
58 changes: 37 additions & 21 deletions src/help.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,31 +31,37 @@ const (
PubKey = "pub"
HelpKey = "help"
QuotaKey = "quota"
ShareKey = "share"
TouchKey = "touch"
TrashKey = "trash"
UnshareKey = "unshare"
UntrashKey = "untrash"
UnpubKey = "unpub"
VersionKey = "version"
)

const (
DescAbout = "print out information about your Google drive"
DescAll = "print out the entire help section"
DescDiff = "compares local files with their remote equivalent"
DescEmptyTrash = "permanently cleans out your trash"
DescFeatures = "returns information about the features of your drive"
DescHelp = "Get help for a topic"
DescInit = "initializes a directory and authenticates user"
DescList = "lists the contents of remote path"
DescQuota = "prints out information related to your quota space"
DescPublish = "publishes a file and prints its publicly available url"
DescPull = "pulls remote changes from Google Drive"
DescPush = "push local changes to Google Drive"
DescTouch = "updates a remote file's modification time to that currently on the server"
DescTrash = "moves files to trash"
DescUntrash = "restores files from trash to their original locations"
DescUnpublish = "revokes public access to a file"
DescVersion = "prints the version"
DescAbout = "print out information about your Google drive"
DescAll = "print out the entire help section"
DescDiff = "compares local files with their remote equivalent"
DescEmptyTrash = "permanently cleans out your trash"
DescFeatures = "returns information about the features of your drive"
DescHelp = "Get help for a topic"
DescInit = "initializes a directory and authenticates user"
DescList = "lists the contents of remote path"
DescQuota = "prints out information related to your quota space"
DescPublish = "publishes a file and prints its publicly available url"
DescPull = "pulls remote changes from Google Drive"
DescPush = "push local changes to Google Drive"
DescShare = "share files with specific emails giving the specified users specifies roles and permissions"
DescTouch = "updates a remote file's modification time to that currently on the server"
DescTrash = "moves files to trash"
DescUnshare = "revoke a user's access to a file"
DescUntrash = "restores files from trash to their original locations"
DescUnpublish = "revokes public access to a file"
DescVersion = "prints the version"
DescAccountType = "\n\t* anyone.\n\t* user.\n\t* domain.\n\t* group"
DescRoles = "\n\t* owner.\n\t* reader.\n\t* writer.\n\t* commenter."
)

var docMap = map[string][]string{
Expand Down Expand Up @@ -91,10 +97,20 @@ var docMap = map[string][]string{
"List the information related a remote path not necessarily present locally",
"Allows printing of long options and by default does minimal printing",
},
PubKey: []string{DescPublish, "Accepts multiple paths"},
QuotaKey: []string{DescQuota},
TouchKey: []string{DescTouch},
TrashKey: []string{DescTrash, "Accepts multiple paths"},
PubKey: []string{DescPublish, "Accepts multiple paths"},
QuotaKey: []string{DescQuota},
ShareKey: []string{
DescShare, "Accepts multiple paths",
"Specify the emails to share with as well as the message to send them on notification",
"Accepted values for:\n+ accountType: ",
DescAccountType, "\n+ roles:", DescRoles,
},
TouchKey: []string{DescTouch},
TrashKey: []string{DescTrash, "Accepts multiple paths"},
UnshareKey: []string{
DescUnshare, "Accepts multiple paths",
"Accepted values for accountTypes::", DescAccountType,
},
UntrashKey: []string{DescUntrash, "Accepts multiple paths"},
UnpubKey: []string{DescUnpublish, "Accepts multiple paths"},
VersionKey: []string{
Expand Down
14 changes: 11 additions & 3 deletions src/remote.go
Original file line number Diff line number Diff line change
Expand Up @@ -243,9 +243,17 @@ func (r *Remote) listPermissions(id string) ([]*drive.Permission, error) {
return res.Items, nil
}

func (r *Remote) insertPermissions(id string, role Role, accountType AccountType) (*drive.Permission, error) {
func (r *Remote) insertPermissions(id, value, emailMessage string, role Role, accountType AccountType) (*drive.Permission, error) {
perm := &drive.Permission{Role: role.String(), Type: accountType.String()}
return r.service.Permissions.Insert(id, perm).Do()
if value != "" {
perm.Value = value
}
req := r.service.Permissions.Insert(id, perm)

if emailMessage != "" {
req = req.EmailMessage(emailMessage)
}
return req.Do()
}

func (r *Remote) deletePermissions(id string, accountType AccountType) error {
Expand All @@ -257,7 +265,7 @@ func (r *Remote) Unpublish(id string) error {
}

func (r *Remote) Publish(id string) (string, error) {
_, err := r.insertPermissions(id, Reader, Anyone)
_, err := r.insertPermissions(id, "", "", Reader, Anyone)
if err != nil {
return "", err
}
Expand Down
113 changes: 110 additions & 3 deletions src/share.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,15 @@ package drive

import (
"fmt"
"strings"
"sync"
)

type AccountType int

const (
Anyone = 1 << iota
UnknownAccountType = 1 << iota
Anyone
User
Domain
Group
Expand All @@ -31,7 +33,8 @@ const (
type Role int

const (
Owner = 1 << iota
UnknownRole = 1 << iota
Owner
Reader
Writer
Commenter
Expand Down Expand Up @@ -65,6 +68,39 @@ func (a *AccountType) String() string {
return "unknown"
}

func stringToRole() func(string) Role {
roleMap := make(map[string]Role)
roles := []Role{UnknownRole, Anyone, User, Domain, Group}
for _, role := range roles {
roleMap[role.String()] = role
}
return func(s string) Role {
r, ok := roleMap[strings.ToLower(s)]
if !ok {
return UnknownRole
}
return r
}
}

func stringToAccountType() func(string) AccountType {
accountMap := make(map[string]AccountType)
accounts := []AccountType{UnknownAccountType, Owner, Reader, Writer, Commenter}
for _, account := range accounts {
accountMap[account.String()] = account
}
return func(s string) AccountType {
a, ok := accountMap[strings.ToLower(s)]
if !ok {
return UnknownAccountType
}
return a
}
}

var reverseRoleResolve = stringToRole()
var reverseAccountTypeResolve = stringToAccountType()

func (g *Commands) resolveRemotePaths(relToRootPaths []string) (files []*File) {
var wg sync.WaitGroup

Expand All @@ -83,6 +119,77 @@ func (g *Commands) resolveRemotePaths(relToRootPaths []string) (files []*File) {
return files
}

func emailsToIds(g *Commands, emails []string) map[string]string {
emailToIds := make(map[string]string)
var wg sync.WaitGroup
wg.Add(len(emails))
for _, email := range emails {
go func(email string, wgg *sync.WaitGroup) {
defer wgg.Done()
emailId, err := g.rem.idForEmail(email)
if err == nil {
emailToIds[email] = emailId
}
}(email, &wg)
}
wg.Wait()
return emailToIds
}

func (c *Commands) Unshare() (err error) {
return c.share(true)
}

func (c *Commands) Share() (err error) {
return fmt.Errorf("Unimplemented")
return c.share(false)
}

func (c *Commands) share(revoke bool) (err error) {
files := c.resolveRemotePaths(c.opts.Sources)

var role Role
var accountType AccountType
var emails []string
var emailMessage string

meta := *c.opts.Meta
if meta != nil {
emailList, eOk := meta["emails"]
if eOk {
emails = emailList
if false {
emailIdMap := emailsToIds(c, emailList)
fmt.Println(emailIdMap)
}
}

roleList, rOk := meta["role"]
if rOk && len(roleList) >= 1 {
role = reverseRoleResolve(roleList[0])
}
accountTypeList, aOk := meta["accountType"]
if aOk {
accountType = reverseAccountTypeResolve(accountTypeList[0])
}

emailMessageList, emOk := meta["emailMessage"]
if emOk && len(emailMessageList) >= 1 {
emailMessage = strings.Join(emailMessageList, "\n")
}
}

for _, file := range files {
if revoke {
if err := c.rem.deletePermissions(file.Id, accountType); err != nil {
return fmt.Errorf("%s: %v", file.Name, err)
}
}
for _, email := range emails {
_, err = c.rem.insertPermissions(file.Id, email, emailMessage, role, accountType)
if err != nil {
return err
}
}
}
return nil
}

0 comments on commit 619fc2d

Please sign in to comment.