2011年12月3日土曜日

Post facebook photo by Command line

access_token に対応したfacebook application名のアルバムに保存される
公開するためには手動で承認作業が必要。
 

fb_image_upload.sh

#!/bin/bash

if [ "$#" -eq 0 ];then
 echo "Do not get image. "
 else
 echo " Get image. "$1
 /opt/local/bin/python2.5 get_image.py $1
fi

msg="test"
caption="message="$msg""
token=`cat .fb_access_token`
echo $caption
echo $token

echo `curl -F "access_token="$token"" -F "source=@"dummy.jpg"" -F "$caption" https://graph.facebook.com/me/photos`

alubm ID によりアルバムを指定して post することもできるが、この場合も公開には承認作業が必要。
echo `curl -F "access_token="$token"" -F "source=@"dummy.jpg"" -F "$caption" https://graph.facebook.com/10150411507966880/photos`
 

アプリケーションで自動作成されるアルバムには1000枚まで写真が保存できるみたいです。

https://graph.facebook.com/ALBUM_ID/photos - The photo will be published to a specific, existing photo album, represented by the ALBUM_ID. Regular albums have a size limit of 200 photos. Default application albums have a size limit of 1000 photos.

https://developers.facebook.com/docs/reference/api/photo/

 

関連
画像の取得 get_image.py

#!-*- coding:utf-8 -*-
#!/opt/local/bin/python2.5

import sys
import urllib
import httplib
import cStringIO
import ImageFile
from PIL import Image, ImageDraw, ImageFont
import string
import re

url = "http://xxx/xxx.jpg"
file = urllib.urlopen(url)
try:
  size = file.headers.get("content-length")
  print "size:" + size
  im = cStringIO.StringIO(file.read())
  img = Image.open(im)

except:
  print "Error: Url = " + url

img_type = "jpg"
img_file = url
if img_file[-3:] == "PNG" or img_file[-3:] == "png":
  img_type = "png"
  img.save("dummy."+ img_type,"PNG")
elif img_file[-3:] == "GIF" or img_file[-3:] == "gif":
  img_type = "gif"
  img.save("dummy."+ img_type,"GIF")
else:
  img.save("dummy."+ img_type,"JPEG")

Get facebook albums by commad line

ポイント
  1. GAEで利用する python2.5 でなくpython2.6以上を利用
    json や urlparse.parse_qs でエラーとなる
    AttributeError: 'module' object has no attribute 'parse_qs'
  2. 'scope':'read_stream,user_photos'
  3. 1度で20件づつしか取得できないので paging が必要となる
    また、先頭の1行のデータは重複する(?)。
  4. http://127.0.0.1:8080/ を登録
     

  5. token が expire している場合は以下のエラーとなるため
    urllib2.HTTPError: HTTP Error 400: Bad Request
    $ rm .fb_access_token

参考
https://sites.google.com/site/benersuayen/lab/facebook     

 

fb_albums.py

#!-*- coding:utf-8 -*-
#!/opt/local/bin/python2.7
import os.path
import json
import urllib2
import urllib
import urlparse
import BaseHTTPServer
import webbrowser

APP_ID = 'XXX'
APP_SECRET = 'XXX'
ENDPOINT = 'graph.facebook.com'
REDIRECT_URI = 'http://127.0.0.1:8080/'
ACCESS_TOKEN = None
LOCAL_FILE = '.fb_access_token'

def get_url(path, args=None):
    args = args or {}
    if ACCESS_TOKEN:
        args['access_token'] = ACCESS_TOKEN
    if 'access_token' in args or 'client_secret' in args:
        endpoint = "https://"+ENDPOINT
    else:
        endpoint = "http://"+ENDPOINT
    return endpoint+path+'?'+urllib.urlencode(args)

def get(path, args=None):
    return urllib2.urlopen(get_url(path, args=args)).read()

def do_next(next,last_id):
    count = 0
    for item in json.loads(get(next))['data']:
        if last_id <> item['id'].encode('utf-8'):
            print "%s, %s" % ( item['id'].encode('utf-8') ,item['name'].encode('utf-8') )
            count = count + 1
    print '---'
    last_id = item['id'].encode('utf-8')
    next = json.loads(get(next))['paging']['next']
    next = next.replace("https://graph.facebook.com/me/albums","/me/albums")
    if next and count > 0:
        do_next(next,last_id)

class RequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):

    def do_GET(self):
        global ACCESS_TOKEN
        self.send_response(200)
        self.send_header("Content-type", "text/html")
        self.end_headers()

        code = urlparse.parse_qs(urlparse.urlparse(self.path).query).get('code')
        code = code[0] if code else None
        if code is None:
            self.wfile.write("Sorry, authentication failed.")
            sys.exit(1)
        response = get('/oauth/access_token', {'client_id':APP_ID,
                                               'redirect_uri':REDIRECT_URI,
                                               'client_secret':APP_SECRET,
                                               'code':code})
        ACCESS_TOKEN = urlparse.parse_qs(response)['access_token'][0]
        open(LOCAL_FILE,'w').write(ACCESS_TOKEN)
        self.wfile.write("You have successfully logged in to facebook. "
                         "You can close this window now.")

if __name__ == '__main__':
    if not os.path.exists(LOCAL_FILE):
        print "Logging you in to facebook..."
        webbrowser.open(get_url('/oauth/authorize',
                                {'client_id':APP_ID,
                                 'redirect_uri':REDIRECT_URI,
                                 'scope':'read_stream,user_photos'}))

        httpd = BaseHTTPServer.HTTPServer(('127.0.0.1', 8080), RequestHandler)
        while ACCESS_TOKEN is None:
            httpd.handle_request()
    else:
        ACCESS_TOKEN = open(LOCAL_FILE).read()
#    for item in json.loads(get('/me/feed'))['data']:
#        if item['type'] == 'status':
#            print item['from']['name'].encode('utf-8')
#            print item['message'].encode('utf-8')
#            if 'comments' in item:
#                for comment in item['comments']['data']:
#                  print comment['from']['name'].encode('utf-8')
#                 print comment['message'].encode('utf-8')
#            print '---'

#   for item in json.loads(get('/me/friends'))['data']:
    for item in json.loads(get('/me/albums'))['data']:
        print "%s, %s" % ( item['id'].encode('utf-8') ,item['name'].encode('utf-8') )
    last_id = item['id'].encode('utf-8')
    print '---'
    next = json.loads(get('/me/albums'))['paging']['next']
    prev = json.loads(get('/me/albums'))['paging']['previous']
#   print  prev
    print  next
    next = next.replace("https://graph.facebook.com/me/albums","/me/albums")
    if next:
        do_next(next,last_id)

2010年1月20日水曜日

Force.com Mail設定

指定の @xxxx.force.com にメールを送信すると Todo あるいはリード(引き合い)として登録される。
























Todo で「すべての未完了」を選択し、登録内容を確認













Todo から必要に応じて

あるいは
リード (取引先などの登録は必要ない)
商談 (取引先の登録が必要)
を作成する

また 製品のサポート対応にはケースを利用する


















ケース画面の製品リストは以下で作成





































設定手順

















システム管理者が組織の [電子メール to Salesforce] を有効化しました。 [電子メール to Salesforce] により、出先からでも、自宅からでも、任意の電子メールアカウントやクライアントから、"電子メール to Salesforce" アドレスに電子メールを BCC すると、送信した電子メールを Salesforce 内のリード、取引先責任者、商談のレコードの活動として電子メールを記録できます。

次のリンクにアクセスして、使用を開始してください。
http://na6.salesforce.com/email/admin/emailToSalesforceUserEdit.apexp

以上、よろしくお願い申し上げます。
xxxxxxx
Salesforce システム管理者


















2010年1月6日水曜日

2009年12月13日日曜日

Task Queue, Transaction

Scheduled Tasks With Cron for Pythonhttp://code.google.com/intl/en/appengine/docs/python/config/cron.html
  • Task Queue戦記 - スティルハウスの書庫
  • TaskQueueをローカルでデバッグする方法 - ひがやすを blog
  • Offline Processing on App Engine: a Look Aheadを見たメモ - スティルハウスの書庫

    タスク Task -- http://code.google.com/intl/ja/appengine/docs/python/taskqueue/overview.html



    やはり追加テーブルとのトランザクションはできない
    けれども、子孫となるテーブルにすればできないこともない

    key_name ="http://pages.google.com/edit/kwin786/Impressionnism01_s.jpg-2"
    r = db.get(db.Key.from_path('Imgmap',key_name))
    db.run_in_transaction(update_imgmap,r.key())

    def update_imgmap(key):
    r = db.get(key)
    r.regimgmapcontenturl = "1"
    s = ImgmapContentUrl(
        key_name=r.content_url,
    #   parent=key,
       content_url = r.content_url)
    s.put()
    r.put()

    Traceback (most recent call last): File "C:\Program Files\Google\google_appengine\google\appengine\ext\webapp\__init__.py", line 507, in __call__ handler.get(*groups) File "C:\google\museum-in-cloud\cron.py", line 70, in get db.run_in_transaction(update_imgmap,r.key()) File "C:\Program Files\Google\google_appengine\google\appengine\api\datastore.py", line 1904, in RunInTransaction DEFAULT_TRANSACTION_RETRIES, function, *args, **kwargs) File "C:\Program Files\Google\google_appengine\google\appengine\api\datastore.py", line 2001, in RunInTransactionCustomRetries result = function(*args, **kwargs) File "C:\google\museum-in-cloud\cron.py", line 148, in update_imgmap s.put() File "C:\Program Files\Google\google_appengine\google\appengine\ext\db\__init__.py", line 797, in put return datastore.Put(self._entity) File "C:\Program Files\Google\google_appengine\google\appengine\api\datastore.py", line 198, in Put tx = _MaybeSetupTransaction(req, keys) File "C:\Program Files\Google\google_appengine\google\appengine\api\datastore.py", line 2090, in _MaybeSetupTransaction raise _DifferentEntityGroupError(expected_group, group) File "C:\Program Files\Google\google_appengine\google\appengine\api\datastore.py", line 2122, in _DifferentEntityGroupError b.kind(), id_or_name(b))) BadRequestError: Cannot operate on different entity groups in a transaction: (kind=u'Imgmap', name=u'http://pages.google.com/edit/kwin786/Impressionnism01_s.jpg-2') and (kind=u'ImgmapContentUrl', name=u'http://pages.google.com/edit/kwin786/Impressionnism01_s.jpg').

  • 2009年9月18日金曜日

    Twitter

    EmbedはQueyを複数指定しするとLoadingのままとなって、NGのようです。











    Swift UI チュートリアル Loading watchOS が終わらない?

    Loading watchOS が終わらない? ディスク容量の残量が少ないので不要なシュミレーターを削除したとこころ watchOSのものが全部なくなってしまっていた。 WatchOS を削除して再度インストールしても復活せず。 Create a new simulator で ...