blob: f939bc0446d9dfc7d408e7da645daadccf2abde4 [file] [log] [blame]
Joe Gregorio695fdc12011-01-16 16:46:55 -05001# Copyright (C) 2010 Google Inc.
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14
15"""Utilities for Google App Engine
16
Joe Gregorio7c22ab22011-02-16 15:32:39 -050017Utilities for making it easier to use OAuth 2.0 on Google App Engine.
Joe Gregorio695fdc12011-01-16 16:46:55 -050018"""
19
20__author__ = 'jcgregorio@google.com (Joe Gregorio)'
21
22import pickle
23
24from google.appengine.ext import db
25from client import Credentials
26from client import Flow
Joe Gregoriodeeb0202011-02-15 14:49:57 -050027from client import Storage
Joe Gregorio695fdc12011-01-16 16:46:55 -050028
29
30class FlowProperty(db.Property):
Joe Gregorio7c22ab22011-02-16 15:32:39 -050031 """App Engine datastore Property for Flow.
32
33 Utility property that allows easy storage and retreival of an
Joe Gregorio695fdc12011-01-16 16:46:55 -050034 oauth2client.Flow"""
35
36 # Tell what the user type is.
37 data_type = Flow
38
39 # For writing to datastore.
40 def get_value_for_datastore(self, model_instance):
41 flow = super(FlowProperty,
42 self).get_value_for_datastore(model_instance)
43 return db.Blob(pickle.dumps(flow))
44
45 # For reading from datastore.
46 def make_value_from_datastore(self, value):
47 if value is None:
48 return None
49 return pickle.loads(value)
50
51 def validate(self, value):
52 if value is not None and not isinstance(value, Flow):
53 raise BadValueError('Property %s must be convertible '
54 'to a FlowThreeLegged instance (%s)' %
55 (self.name, value))
56 return super(FlowProperty, self).validate(value)
57
58 def empty(self, value):
59 return not value
60
61
62class CredentialsProperty(db.Property):
Joe Gregorio7c22ab22011-02-16 15:32:39 -050063 """App Engine datastore Property for Credentials.
64
65 Utility property that allows easy storage and retrieval of
Joe Gregorio695fdc12011-01-16 16:46:55 -050066 oath2client.Credentials
67 """
68
69 # Tell what the user type is.
70 data_type = Credentials
71
72 # For writing to datastore.
73 def get_value_for_datastore(self, model_instance):
74 cred = super(CredentialsProperty,
75 self).get_value_for_datastore(model_instance)
76 return db.Blob(pickle.dumps(cred))
77
78 # For reading from datastore.
79 def make_value_from_datastore(self, value):
80 if value is None:
81 return None
82 return pickle.loads(value)
83
84 def validate(self, value):
85 if value is not None and not isinstance(value, Credentials):
86 raise BadValueError('Property %s must be convertible '
87 'to an Credentials instance (%s)' %
88 (self.name, value))
89 return super(CredentialsProperty, self).validate(value)
90
91 def empty(self, value):
92 return not value
93
94
Joe Gregoriodeeb0202011-02-15 14:49:57 -050095class StorageByKeyName(Storage):
Joe Gregorio695fdc12011-01-16 16:46:55 -050096 """Store and retrieve a single credential to and from
97 the App Engine datastore.
98
99 This Storage helper presumes the Credentials
100 have been stored as a CredenialsProperty
101 on a datastore model class, and that entities
102 are stored by key_name.
103 """
104
105 def __init__(self, model, key_name, property_name):
106 """Constructor for Storage.
107
108 Args:
109 model: db.Model, model class
110 key_name: string, key name for the entity that has the credentials
111 property_name: string, name of the property that is an CredentialsProperty
112 """
Joe Gregorio7c22ab22011-02-16 15:32:39 -0500113 self._model = model
114 self._key_name = key_name
115 self._property_name = property_name
Joe Gregorio695fdc12011-01-16 16:46:55 -0500116
117 def get(self):
118 """Retrieve Credential from datastore.
119
120 Returns:
121 oauth2client.Credentials
122 """
Joe Gregorio7c22ab22011-02-16 15:32:39 -0500123 entity = self._model.get_or_insert(self._key_name)
124 credential = getattr(entity, self._property_name)
Joe Gregorio695fdc12011-01-16 16:46:55 -0500125 if credential and hasattr(credential, 'set_store'):
126 credential.set_store(self.put)
127 return credential
128
129 def put(self, credentials):
130 """Write a Credentials to the datastore.
131
132 Args:
133 credentials: Credentials, the credentials to store.
134 """
Joe Gregorio7c22ab22011-02-16 15:32:39 -0500135 entity = self._model.get_or_insert(self._key_name)
136 setattr(entity, self._property_name, credentials)
Joe Gregorio695fdc12011-01-16 16:46:55 -0500137 entity.put()