1
0
This repository has been archived on 2021-04-26. You can view files and clone it, but cannot push or open issues or pull requests.
gallery3-contrib/3.0/client/Python/pylibgal3/libg3/Gallery3.py
2010-12-26 15:39:17 +08:00

465 lines
16 KiB
Python

#
# Author: Jay Deiman
# Email: admin@splitstreams.com
#
# This file is part of pylibgal3.
#
# pylibgal3 is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# pylibgal3 is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with pylibgal3. If not, see <http://www.gnu.org/licenses/>.
#
__all__ = ['Gallery3' , 'login']
from Requests import *
from Errors import G3RequestError , G3UnknownError
from G3Items import getItemFromResp , getItemsFromResp , BaseRemote , Album , \
RemoteImage , Tag
from urllib import quote , urlencode
from uuid import uuid4
import urllib2 , os , json
class Gallery3(object):
"""
This is the main utility class that should be instantiated and used for all
calls
"""
def __init__(self , host , apiKey , g3Base='/gallery3' , port=80 ,
ssl=False):
"""
Initializes and sets up the gallery 3 object
host(str) : The hostname of the gallery site
apiKey(str) : The api key to use for the connections
g3Base(str) : The remote url path to your gallery 3 install
(default: /gallery3)
port(int) : The port number to connect to (default: 80)
ssl(bool) : If true, use SSL for the connection (default: 80)
"""
self.host = host
self.apiKey = apiKey
self.port = int(port)
self.ssl = ssl
self.g3Base = g3Base.strip('/')
self.protocol = ('http' , 'https')[ssl]
self.root = None
self._rootUri = 'index.php/rest/item/1'
self._opener = None
self._buildOpener()
def getRoot(self):
"""
Returns the root item (album)
"""
if self.root is None:
resp = self.getRespFromUri(self._rootUri)
self.root = getItemFromResp(resp , self)
return self.root
def getRandomImage(self , album , direct=True):
"""
Returns a random RemoteImage object for the album. If "direct" is
False, a random image can be pulled from nested albums.
album(Album) : The album object to pull the random image from
direct(bool) : If set to False, the image may be pulled from
a sub-album
returns(RemoteImage) : Returns a RemoteImage instance
"""
scope = ('all' , 'direct')[direct]
data = {
'type': 'photo' ,
'random': 'true' ,
'scope': scope ,
}
url = '%s?%s' % (album.url , urlencode(data))
resp = self.getRespFromUrl(url)
return getItemFromResp(resp , self)
def getItemsForUrls(self , urls , parent=None):
"""
This retrieves an item for each url specified in the urls list
urls(list[str]) : The list of urls to retrieve
returns(list[BaseRemote]) : Returns a list of the corresponding
remote objects
"""
numUrls = len(urls)
start = 0
increment = 25
ret = []
while start < numUrls:
data = {
'urls': json.dumps(urls[start:start+increment]) ,
'num': str(increment) ,
'start': str(start) ,
}
resp = self.getRespFromUri('index.php/rest/items' , data)
ret.extend(getItemsFromResp(resp , self , parent))
start += increment
return ret
def getRespFromUrl(self , url):
"""
This returns the response object given a full url rather than just a
uri defining the location on the server
url(str) : The url to the resource
"""
req = GetRequest(url , self.apiKey)
resp = self._openReq(req)
return resp
def getRespFromUri(self , uri , kwargs={}):
"""
Performs the request for the given uri and returns the "addinfourl"
response
uri(str) : The uri string defining the resource on the defined host
"""
url = self._buildUrl(uri , kwargs)
print url
return self.getRespFromUrl(url)
def addAlbum(self , parent , albumName , title , description=''):
"""
Adds an album to the given parent album
parent(Album) : The parent Album object
albumName(str) : The name of the album
title(str) : The album title
description(str) : The album description
returns(Album) : The Album object that was created
"""
if not parent.can_edit:
raise G3AuthError('You do not have permission to edit: %s' %
parent.title)
data = {
'type': 'album' ,
'name': albumName ,
'title': title ,
'description': description ,
}
req = PostRequest(parent.url , self.apiKey , data)
resp = self._openReq(req)
newObjUrl = self._getUrlFromResp(resp)
item = getItemFromResp(self.getRespFromUrl(newObjUrl) , self , parent)
parent._members.append(newObjUrl)
parent.members.append(item)
return item
def addImage(self , parent , image , title='' , description='' , name=''):
"""
Add a LocalImage to the parent album.
parent(Album) : The parent album to add the image to
image(LocalImage) : The local image to upload and add to the
parent
title(str) : The image title
description(str) : The image description
name(str) : The image file name
returns(RemoteImage) : The RemoteImage instance for the item
uploaded
"""
if not parent.can_edit:
raise G3AuthError('You do not have permission to edit: %s' %
parent.title)
if name:
image.Filename = name
entity = {
'name': image.filename ,
'type': image.type ,
'title': title ,
'description': description ,
}
boundary = str(uuid4())
headers = {'Content-Type': 'multipart/form-data; boundary=%s' %
boundary}
# this is more complicated than adding an album. We have to
# construct the upload MIME headers, including build the string
# data section
data = '--%s\r\n' % boundary
data += 'Content-Disposition: form-data; name="entity"\r\n'
data += 'Content-Type: text/plain; ' \
'charset=UTF-8\r\n'
data += 'Content-Transfer-Encoding: 8bit\r\n'
data += '\r\n'
data += '%s\r\n' % json.dumps(entity , separators=(',' , ':'))
data += '--%s\r\n' % boundary
data += image.getUploadContent()
data += '--%s--\r\n' % boundary
req = PostRequest(parent.url , self.apiKey , data , headers)
resp = self._openReq(req)
newObjUrl = self._getUrlFromResp(resp)
item = getItemFromResp(self.getRespFromUrl(newObjUrl) , self , parent)
parent._members.append(newObjUrl)
parent.members.append(item)
return item
def addMovie(self , parent , movie , title='' , description='' , name=''):
"""
Add a LocalMovie to the parent album.
parent(Album) : The parent album to add the movie to
image(LocalMovie) : The local movie to upload and add to the
parent
title(str) : The movie title
description(str) : The movie description
name(str) : The movie file name
returns(RemoteMovie) : The RemoteMovie instance for the movie
uploaded
"""
return self.addImage(parent , movie , title , description , name)
def setAlbumCover(self , album , image):
"""
Updates a remote item's title and description
album(Album) : The album to set the cover on
image(RemoteImage) : The image to use as the cover
returns(tuple(status , msg)) : Returns a tuple of a boolean status
and a message if there is an error
"""
if not album.can_edit:
raise G3AuthError('You do not have permission to edit: %s' %
album.title)
try:
self._isItemValid(album , Album)
self._isItemValid(image , RemoteImage)
except Exception , e:
return (False , str(e))
data = {
'album_cover': image.url ,
}
req = PutRequest(album.url , self.apiKey , data)
try:
resp = self._openReq(req)
except G3RequestError , e:
return (False , str(e))
album.album_cover = image
album._album_cover = image.url
return (True , '')
def updateItem(self , item):
"""
Updates a remote item's title and description
item(BaseRemote) : An item descended from BaseRemote
returns(tuple(status , msg)) : Returns a tuple of a boolean status
and a message if there is an error
"""
if not item.can_edit:
raise G3AuthError('You do not have permission to edit: %s' %
item.title)
try:
self._isItemValid(item , BaseRemote)
except Exception , e:
return (False , str(e))
data = {
'title': item.title ,
'description': item.description ,
}
req = PutRequest(item.url , self.apiKey , data)
try:
resp = self._openReq(req)
except G3RequestError , e:
return (False , str(e))
return (True , '')
def updateAlbum(self , album):
"""
Update the title and description for an album.
image(Album) : Updates the title and/or description
for the Album
returns(tuple(status , msg)) : Returns a tuple of a boolean status
and a message if there is an error
"""
return self.updateItem(album)
def updateImage(self , image):
"""
Update the title and description for an image.
image(RemoteImage) : Updates the title and/or description for the
RemoteImage
returns(tuple(status , msg)) : Returns a tuple of a boolean status
and a message if there is an error
"""
return self.updateItem(image)
def updateMovie(self , movie):
"""
Update the title and description for a movie.
image(RemoteMovie) : Updates the title and/or description for the
RemoteMovie
returns(tuple(status , msg)) : Returns a tuple of a boolean status
and a message if there is an error
"""
return self.updateItem(movie)
def deleteItem(self , item):
"""
Deletes the given item. Item must be descended from BaseRemote.
item(BaseRemote) : The item to delete
returns(tuple(status , msg)) : Returns a tuple of a boolean status
and a message if there is an error
"""
if not item.can_edit:
raise G3AuthError('You do not have permission to edit: %s' %
item.title)
try:
self._isItemValid(item , BaseRemote)
except Exception , e:
return (False , e.message)
req = DeleteRequest(item.url , self.apiKey)
try:
resp = self._openReq(req)
except G3RequestError , e:
return (False , e.message)
return (True , '')
def tagItem(self , item , tagName):
"""
Tag this item with the string "tagName"
tagName(str) : The actual tag name
returns(Tag) : The tag that was created
"""
# First we have to create the tag itself, if necessary
data = {
'name': str(tagName) ,
}
url = self._buildUrl('index.php/rest/tags')
req = PostRequest(url , self.apiKey , data)
resp = self._openReq(req)
r = json.loads(resp.read())
tagUrl = r['url']
# And now that we have our (possibly) newly created tag, we can
# use that to tag our item
data = {
'tag': tagUrl ,
'item': item.url ,
}
url = self._buildUrl('index.php/rest/item_tags/%s' % item.id)
req = PostRequest(url , self.apiKey , data)
resp = self._openReq(req)
respObj = json.loads(resp.read())
item.relationships['tags']['members'].append(respObj['url'])
tag = Tag(respObj , self , item)
if hasattr(item , 'tags'):
item.tags.append(tag)
return tag
def addComment(self , image , comment):
"""
Comment on this item with the string "comment"
comment(str) : The comment
returns(Comment) : The comment that was created
"""
data = {
'item': image.url ,
'text': comment ,
}
url = self._buildUrl('index.php/rest/comments')
req = PostRequest(url , self.apiKey , data)
resp = self._openReq(req)
commUrl = json.loads(resp.read())['url']
resp = self.getRespFromUrl(commUrl)
comm = getItemFromResp(resp , self , image)
if hasattr(image , 'comments'):
image.comments.append(comm)
return comm
def _buildOpener(self):
cp = urllib2.HTTPCookieProcessor()
self._opener = urllib2.build_opener(cp)
if self.ssl:
self._opener.add_handler(urllib2.HTTPSHandler())
def _buildUrl(self , resource , kwargs={}):
url = '%s://%s:%d/%s/%s' % (self.protocol , self.host , self.port ,
quote(self.g3Base) , quote(resource))
if kwargs:
url += '?%s' % urlencode(kwargs)
return url
def _getUrlFromResp(self , resp):
d = json.loads(resp.read())
return d['url']
def _openReq(self , req):
try:
resp = self._opener.open(req)
except urllib2.HTTPError , e:
err = json.loads(e.read())
if isinstance(err , dict) and 'errors' in err:
raise G3RequestError(err['errors'])
else:
raise G3UnknownError('Unknown request error: %s' % e)
return resp
def _isItemValid(self , item , cls):
if not isinstance(item , cls):
raise TypeError('Items to be modified must be descended from '
'%s: %s' % (cls , type(item)))
if not 'url' in item.__dict__:
raise G3UnknownError('The object, %s, has no "url"' % item)
def login(host , username , passwd , g3Base='/gallery3' , port=80 ,
ssl=False):
"""
This will log you in and return a Gallery3 object on success, None
otherwise
host(str) : The hostname of the gallery site
username(str) : The username to login with
passwd(str) : The password to login with
g3Base(str) : The remote url path to your gallery 3 install
(default: /gallery3)
port(int) : The port number to connect to (default: 80)
ssl(bool) : If true, use SSL for the connection (default: 80)
"""
data = {
'user': username ,
'password': passwd ,
}
protocol = ('http' , 'https')[ssl]
url = '%s://%s:%d/%s/index.php/rest' % (protocol , host , port ,
quote(g3Base))
req = PostRequest(url , None , urlencode(data))
opener = urllib2.build_opener()
if ssl:
opener.add_handler(urllib2.HTTPSHandler())
try:
resp = opener.open(req)
except urllib2.HTTPError , e:
return None
apiKey = resp.read().strip('\'"')
return Gallery3(host , apiKey , g3Base , port , ssl)