Home Download Docs Code Community
     1	/*
     2	Copyright 2014 The Perkeep Authors
     3	
     4	Licensed under the Apache License, Version 2.0 (the "License");
     5	you may not use this file except in compliance with the License.
     6	You may obtain a copy of the License at
     7	
     8	     http://www.apache.org/licenses/LICENSE-2.0
     9	
    10	Unless required by applicable law or agreed to in writing, software
    11	distributed under the License is distributed on an "AS IS" BASIS,
    12	WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13	See the License for the specific language governing permissions and
    14	limitations under the License.
    15	*/
    16	
    17	package picasa
    18	
    19	import (
    20		"encoding/xml"
    21		"fmt"
    22		"log"
    23		"net/http"
    24		"os"
    25		"path/filepath"
    26		"time"
    27	
    28		"perkeep.org/internal/httputil"
    29		"perkeep.org/internal/osutil"
    30		"perkeep.org/pkg/blob"
    31		"perkeep.org/pkg/importer"
    32	
    33		"github.com/tgulacsi/picago"
    34	)
    35	
    36	var _ importer.TestDataMaker = (*imp)(nil)
    37	
    38	func (im *imp) SetTestAccount(acctNode *importer.Object) error {
    39		// TODO(mpl): refactor with twitter
    40		return acctNode.SetAttrs(
    41			importer.AcctAttrAccessToken, "fakeAccessToken",
    42			importer.AcctAttrAccessTokenSecret, "fakeAccessSecret",
    43			importer.AcctAttrUserID, "fakeUserId",
    44			importer.AcctAttrName, "fakeName",
    45			importer.AcctAttrUserName, "fakeScreenName",
    46		)
    47	}
    48	
    49	func (im *imp) MakeTestData() http.RoundTripper {
    50	
    51		const (
    52			apiURL        = "https://picasaweb.google.com/data/feed/api"
    53			nAlbums       = 10 // Arbitrary number of albums generated.
    54			nEntries      = 3  // number of albums or photos returned in the feed at each call.
    55			defaultUserId = "default"
    56		)
    57	
    58		albumsListCached := make(map[int]string)
    59		okHeader := `HTTP/1.1 200 OK
    60	Content-Type: application/json; charset=UTF-8
    61	
    62	`
    63	
    64		responses := make(map[string]func() *http.Response)
    65	
    66		// register the get albums list calls
    67		for i := 1; i < nAlbums+1; i += nEntries {
    68			url := fmt.Sprintf("%s/user/%s?start-index=%d", apiURL, defaultUserId, i)
    69			response := okHeader + fakeAlbumsList(i, nAlbums, nEntries, albumsListCached)
    70			responses[url] = httputil.StaticResponder(response)
    71		}
    72	
    73		// register the get album calls
    74		for i := 1; i < nAlbums+1; i++ {
    75			albumId := blob.RefFromString(fmt.Sprintf("Album %d", i)).DigestPrefix(10)
    76			for j := 1; j < i+1; j += nEntries {
    77				url := fmt.Sprintf("%s/user/%s/albumid/%s?imgmax=d&start-index=%d", apiURL, defaultUserId, albumId, j)
    78				// Using i as nTotal argument means album N will have N photos in it.
    79				response := okHeader + fakePhotosList(j, i, nEntries)
    80				responses[url] = httputil.StaticResponder(response)
    81			}
    82		}
    83	
    84		// register the photo download calls
    85		pudgyPic := fakePhoto()
    86		photoURL1 := "https://perkeep.org/pic/pudgy1.png"
    87		photoURL2 := "https://perkeep.org/pic/pudgy2.png"
    88		responses[photoURL1] = httputil.FileResponder(pudgyPic)
    89		responses[photoURL2] = httputil.FileResponder(pudgyPic)
    90	
    91		return httputil.NewFakeTransport(responses)
    92	}
    93	
    94	// fakeAlbumsList returns an xml feed of albums. The feed starts at index, and
    95	// ends at index + nEntries (exclusive), or at nTotal (inclusive), whichever is the
    96	// lowest.
    97	func fakeAlbumsList(index, nTotal, nEntries int, cached map[int]string) string {
    98		if cl, ok := cached[index]; ok {
    99			return cl
   100		}
   101	
   102		max := index + nEntries
   103		if max > nTotal+1 {
   104			max = nTotal + 1
   105		}
   106		var entries []picago.Entry
   107		for i := index; i < max; i++ {
   108			entries = append(entries, fakeAlbum(i))
   109		}
   110		atom := &picago.Atom{
   111			TotalResults: nTotal,
   112			Entries:      entries,
   113		}
   114	
   115		feed, err := xml.MarshalIndent(atom, "", "	")
   116		if err != nil {
   117			log.Fatalf("%v", err)
   118		}
   119		cached[index] = string(feed)
   120		return cached[index]
   121	}
   122	
   123	func fakeAlbum(counter int) picago.Entry {
   124		author := picago.Author{
   125			Name: "fakeAuthorName",
   126		}
   127		media := &picago.Media{
   128			Description: "fakeAlbumDescription",
   129			Keywords:    "fakeKeyword1,fakeKeyword2",
   130		}
   131		title := fmt.Sprintf("Album %d", counter)
   132		year := time.Hour * 24 * 365
   133		month := year / 12
   134		return picago.Entry{
   135			ID:        blob.RefFromString(title).DigestPrefix(10),
   136			Published: time.Now().Add(-time.Duration(counter) * year),
   137			Updated:   time.Now().Add(-time.Duration(counter) * month),
   138			Name:      "fakeAlbumName",
   139			Title:     title,
   140			Summary:   "fakeAlbumSummary",
   141			Location:  "fakeAlbumLocation",
   142			Author:    author,
   143			Media:     media,
   144		}
   145	}
   146	
   147	// fakePhotosList returns an xml feed of an album's photos. The feed starts at
   148	// index, and ends at index + nEntries (exclusive), or at nTotal (inclusive),
   149	// whichever is the lowest.
   150	func fakePhotosList(index, nTotal, nEntries int) string {
   151		max := index + nEntries
   152		if max > nTotal+1 {
   153			max = nTotal + 1
   154		}
   155		var entries []picago.Entry
   156		for i := index; i < max; i++ {
   157			entries = append(entries, fakePhotoEntry(i, nTotal))
   158		}
   159		atom := &picago.Atom{
   160			NumPhotos: nTotal,
   161			Entries:   entries,
   162		}
   163	
   164		feed, err := xml.MarshalIndent(atom, "", "	")
   165		if err != nil {
   166			log.Fatalf("%v", err)
   167		}
   168		return string(feed)
   169	}
   170	
   171	func fakePhotoEntry(photoNbr int, albumNbr int) picago.Entry {
   172		var content picago.EntryContent
   173		if photoNbr%2 == 0 {
   174			content = picago.EntryContent{
   175				URL:  "https://perkeep.org/pic/pudgy1.png",
   176				Type: "image/png",
   177			}
   178		}
   179		var point string
   180		if photoNbr%3 == 0 {
   181			point = "37.7447124 -122.4341914"
   182		} else {
   183			point = "45.1822842 5.7141854"
   184		}
   185		mediaContent := picago.MediaContent{
   186			URL:  "https://perkeep.org/pic/pudgy2.png",
   187			Type: "image/png",
   188		}
   189		media := &picago.Media{
   190			Title:       "fakePhotoTitle",
   191			Description: "fakePhotoDescription",
   192			Keywords:    "fakeKeyword1,fakeKeyword2",
   193			Content:     []picago.MediaContent{mediaContent},
   194		}
   195		// to be consistent, all the pics times should be anterior to their respective albums times. whatever.
   196		day := time.Hour * 24
   197		year := day * 365
   198		created := time.Now().Add(-time.Duration(photoNbr) * year)
   199		published := created.Add(day)
   200		updated := published.Add(day)
   201	
   202		exif := &picago.Exif{
   203			FStop:       7.7,
   204			Make:        "whatisthis?", // not obvious to me, needs doc in picago
   205			Model:       "potato",
   206			Exposure:    7.7,
   207			Flash:       false,
   208			FocalLength: 7.7,
   209			ISO:         100,
   210			Timestamp:   created.Unix(),
   211			UID:         "whatisthis?", // not obvious to me, needs doc in picago
   212		}
   213	
   214		title := fmt.Sprintf("Photo %d of album %d", photoNbr, albumNbr)
   215		return picago.Entry{
   216			ID:        blob.RefFromString(title).DigestPrefix(10),
   217			Exif:      exif,
   218			Summary:   "fakePhotoSummary",
   219			Title:     title,
   220			Location:  "fakePhotoLocation",
   221			Published: published,
   222			Updated:   updated,
   223			Media:     media,
   224			Point:     point,
   225			Content:   content,
   226		}
   227	}
   228	
   229	// TODO(mpl): refactor with twitter
   230	func fakePhoto() string {
   231		camliDir, err := osutil.GoPackagePath("perkeep.org")
   232		if err == os.ErrNotExist {
   233			log.Fatal("Directory \"perkeep.org\" not found under GOPATH/src; are you not running with devcam?")
   234		}
   235		if err != nil {
   236			log.Fatalf("Error searching for \"perkeep.org\" under GOPATH: %v", err)
   237		}
   238		return filepath.Join(camliDir, filepath.FromSlash("clients/web/embed/glitch/npc_piggy__x1_walk_png_1354829432.png"))
   239	}
Website layout inspired by memcached.
Content by the authors.