github.com/aleksi/gonuts.io@v0.0.0-20130622121132-3b0f2d1999fb/app/gonuts/models.go (about)

     1  package gonuts
     2  
     3  import (
     4  	"appengine"
     5  	"appengine/datastore"
     6  	"appengine/user"
     7  	"crypto/rand"
     8  	"crypto/sha1"
     9  	"encoding/hex"
    10  	"fmt"
    11  	"io"
    12  	"sort"
    13  	"time"
    14  )
    15  
    16  type User struct {
    17  	// StringID (entity name, key name) is appengine/user.User.ID
    18  	Id                string // same as StringID
    19  	Email             string
    20  	FederatedIdentity string
    21  	Token             string
    22  	Debug             bool
    23  	Vendors           []string
    24  }
    25  
    26  func UserKey(c appengine.Context, u *user.User) *datastore.Key {
    27  	return datastore.NewKey(c, "User", u.ID, 0, nil)
    28  }
    29  
    30  func (user *User) AddVendor(vendor *Vendor) {
    31  	vmap := make(map[string]bool, len(user.Vendors)+1)
    32  	for _, v := range user.Vendors {
    33  		vmap[v] = true
    34  	}
    35  	vmap[vendor.Vendor] = true
    36  
    37  	vendors := make([]string, 0, len(vmap))
    38  	for v := range vmap {
    39  		vendors = append(vendors, v)
    40  	}
    41  	sort.Strings(vendors)
    42  	user.Vendors = vendors
    43  
    44  	umap := make(map[string]bool, len(vendor.UserStringID)+1)
    45  	for _, u := range vendor.UserStringID {
    46  		umap[u] = true
    47  	}
    48  	umap[user.Id] = true
    49  
    50  	users := make([]string, 0, len(umap))
    51  	for u := range umap {
    52  		users = append(users, u)
    53  	}
    54  	sort.Strings(users)
    55  	vendor.UserStringID = users
    56  }
    57  
    58  func (user *User) Identifier() (id string) {
    59  	id = user.Email
    60  	if id == "" {
    61  		id = user.FederatedIdentity
    62  	}
    63  	if id == "" {
    64  		panic(fmt.Errorf("User %#v has neither email nor federated identity.", user))
    65  	}
    66  	return
    67  }
    68  
    69  type Vendor struct {
    70  	// StringID (entity name, key name) is "Vendor"
    71  	Vendor       string
    72  	UserStringID []string // slice of User.StringID
    73  }
    74  
    75  func VendorKey(c appengine.Context, vendor string) *datastore.Key {
    76  	return datastore.NewKey(c, "Vendor", vendor, 0, nil)
    77  }
    78  
    79  type Nut struct {
    80  	// StringID (entity name, key name) is "Vendor/Name"
    81  	Vendor string
    82  	Name   string
    83  	Doc    string // Doc of latest published version
    84  	// TODO store total number of downloads, update by cron
    85  }
    86  
    87  func NutKey(c appengine.Context, vendor, nut string) *datastore.Key {
    88  	return datastore.NewKey(c, "Nut", fmt.Sprintf("%s/%s", vendor, nut), 0, nil)
    89  }
    90  
    91  type Version struct {
    92  	// StringID (entity name, key name) is "Vendor/Name-Version"
    93  	Vendor     string
    94  	Name       string
    95  	Version    string
    96  	VersionNum int // for sorting
    97  	Doc        string
    98  	Homepage   string
    99  	BlobKey    appengine.BlobKey
   100  	CreatedAt  time.Time
   101  	Downloads  int
   102  }
   103  
   104  func VersionKey(c appengine.Context, vendor, nut, version string) *datastore.Key {
   105  	return datastore.NewKey(c, "Version", fmt.Sprintf("%s/%s-%s", vendor, nut, version), 0, nil)
   106  }
   107  
   108  func (user *User) GenerateToken() (err error) {
   109  	const n = 4096
   110  
   111  	buf := make([]byte, n)
   112  	_, err = io.ReadAtLeast(rand.Reader, buf, n)
   113  	if err != nil {
   114  		return
   115  	}
   116  
   117  	h := sha1.New()
   118  	_, err = h.Write(buf)
   119  	if err != nil {
   120  		return
   121  	}
   122  
   123  	user.Token = hex.EncodeToString(h.Sum(nil))
   124  	return
   125  }