~ubuntu-branches/ubuntu/wily/tdiary/wily

« back to all changes in this revision

Viewing changes to contrib2/plugin/profile.rb

  • Committer: Bazaar Package Importer
  • Author(s): Daigo Moriwaki
  • Date: 2011-04-11 21:53:16 UTC
  • mfrom: (1.2.3 upstream)
  • Revision ID: james.westby@ubuntu.com-20110411215316-ih4gt4q8p29d2wf8
Tags: 3.0.1-1
* New upstream release (Closes: #542801, #594947)
* debian/control:
 - Bumped up Standards-Version to 3.9.1.
 - Updated version dependency.
* debian/tdiary-setup.rb: Followed the upstream changes, incorporating js and
  index.fcgi

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#
 
2
# profile.rb: profile plugin for tDiary
 
3
#
 
4
# usage:
 
5
#   profile(id[, service = :twitter])
 
6
#   - id: user ID for profile service
 
7
#   - service: profile service (default is :twitter)
 
8
#     Choose from :github, :twitter, :friendfeed, :iddy
 
9
#
 
10
# Copyright (C) 2009 by MATSUOKA Kohei < http://www.machu.jp/ >
 
11
# Distributed under the GPL.
 
12
#
 
13
require 'timeout'
 
14
require 'rexml/document'
 
15
require 'open-uri'
 
16
require 'digest/md5'
 
17
#require 'yaml/store'
 
18
require 'pstore'
 
19
 
 
20
module ::Profile
 
21
  module Service
 
22
    # base class for profile services
 
23
    class Base
 
24
      # default attributes
 
25
      attr_reader :id
 
26
      attr_reader :image
 
27
      attr_reader :name
 
28
      attr_reader :mail
 
29
      attr_reader :description
 
30
      attr_reader :link
 
31
 
 
32
      # class instance variables
 
33
      class << self
 
34
        attr_reader :properties
 
35
        attr_reader :endpoint_proc
 
36
      end
 
37
 
 
38
      # set property and xpath pair for parse XML document
 
39
      def self.property(property, path)
 
40
        @properties ||= {}
 
41
        @properties[property] = path
 
42
      end
 
43
 
 
44
      # set endpoint proc (this proc is called by initialize method with id)
 
45
      def self.endpoint(&block)
 
46
        @endpoint_proc = block
 
47
      end
 
48
 
 
49
      def initialize(id, options = {})
 
50
        @id = id
 
51
        @options = options
 
52
 
 
53
        if self.class.endpoint_proc
 
54
          endpoint = self.class.endpoint_proc.call(id)
 
55
          doc = fetch(endpoint)
 
56
          parse(doc)
 
57
        end
 
58
      end
 
59
 
 
60
      # get a XML document from endpoint and create REXML::Document instance
 
61
      def fetch(endpoint)
 
62
        timeout(5) do
 
63
          open(endpoint) do |f|
 
64
            doc = REXML::Document.new(f)
 
65
          end
 
66
        end
 
67
      end
 
68
 
 
69
      # parse XML document with properties
 
70
      def parse(doc)
 
71
        self.class.properties.each do |property, path|
 
72
          if doc.elements[path]
 
73
            value = doc.elements[path].text
 
74
            instance_variable_set("@#{property}", value)
 
75
          end
 
76
        end
 
77
      end
 
78
    end
 
79
 
 
80
    # github.com
 
81
    class GitHub < Base
 
82
      property :name, '//user/name'
 
83
      property :mail, '//user/email'
 
84
      endpoint {|id| "http://github.com/api/v2/xml/user/show/#{id}" }
 
85
 
 
86
      def image
 
87
        Gravatar.new(@mail, @options).image
 
88
        # "http://www.gravatar.com/avatar/#{Digest::MD5.hexdigest(@mail)}.jpg"
 
89
      end
 
90
 
 
91
      def link
 
92
        "http://github.com/#{@id}"
 
93
      end
 
94
    end
 
95
 
 
96
    # twitter.com
 
97
    class Twitter < Base
 
98
      property :name, '//user/name'
 
99
      property :image, '//user/profile_image_url'
 
100
      property :description, '//user/description'
 
101
      endpoint {|id| "http://twitter.com/users/show/#{id}.xml" }
 
102
 
 
103
      def link
 
104
        "http://twitter.com/#{@id}"
 
105
      end
 
106
    end
 
107
 
 
108
    # friendfeed.com
 
109
    class FriendFeed < Base
 
110
      property :name, '//feed/name'
 
111
      property :description, '//feed/description'
 
112
      endpoint {|id| "http://friendfeed-api.com/v2/feed/#{id}?format=xml&num=0" }
 
113
 
 
114
      def image
 
115
        "http://friendfeed-api.com/v2/picture/#{id}"
 
116
      end
 
117
 
 
118
      def link
 
119
        "http://friendfeed.com/#{@id}"
 
120
      end
 
121
    end
 
122
 
 
123
    # iddy.jp
 
124
    # this class is based on iddy.rb
 
125
    class Iddy < Base
 
126
      ######################################################################
 
127
      # If you will modify or release another version of this code,
 
128
      # please get your own application key from iddy.jp and replace below.
 
129
      ######################################################################
 
130
      API_KEY = '9262ea8ffba962aabb4f1a1d3f1cfa953b11aa23' unless defined? API_KEY
 
131
 
 
132
      property :name, '//response/users/user/accountname'
 
133
      property :image, '//response/users/user/imageurl'
 
134
      property :description, '/response/users/user/profile'
 
135
      endpoint {|id| "http://iddy.jp/api/user/?apikey=#{API_KEY}&accountname=#{id}" }
 
136
 
 
137
      def link
 
138
        "http://iddy.jp/profile/#{@id}/"
 
139
      end
 
140
    end
 
141
 
 
142
    # gravatar.com
 
143
    class Gravatar < Base
 
144
      def image
 
145
        size = @options[:size] ? "?s=#{@options[:size]}" : ""
 
146
        "http://www.gravatar.com/avatar/#{Digest::MD5.hexdigest(@id.downcase)}.jpg#{size}"
 
147
      end
 
148
    end
 
149
 
 
150
    class Wassr < Base
 
151
      property :image, '//statuses/status/user/profile_image_url'
 
152
      endpoint {|id| "http://api.wassr.jp/statuses/show.xml?id=#{id}" }
 
153
 
 
154
      def link
 
155
        "http://wassr.jp/user/#{id}"
 
156
      end
 
157
    end
 
158
 
 
159
    class Hatena < Base
 
160
      def image
 
161
        prefix = id[0..1]
 
162
        "http://www.hatena.ne.jp/users/#{prefix}/#{id}/profile.gif"
 
163
      end
 
164
 
 
165
      def link
 
166
        "http://www.hatena.ne.jp/#{id}/"
 
167
      end
 
168
    end
 
169
  end
 
170
end
 
171
 
 
172
PROFILE_VERSION = '20090909'
 
173
 
 
174
def profile(id, service = :twitter, options = {})
 
175
  html = ''
 
176
 
 
177
  service_class = {
 
178
    :twitter => Profile::Service::Twitter,
 
179
    :github => Profile::Service::GitHub,
 
180
    :friendfeed => Profile::Service::FriendFeed,
 
181
    :iddy => Profile::Service::Iddy,
 
182
    :gravatar => Profile::Service::Gravatar,
 
183
    :wassr => Profile::Service::Wassr,
 
184
    :hatena => Profile::Service::Hatena,
 
185
  }[service.to_s.downcase.to_sym]
 
186
 
 
187
  # TODO: create cache manager class
 
188
 
 
189
  # cache = "#{@cache_path}/profile.yaml"
 
190
  cache = "#{@cache_path}/profile.pstore"
 
191
  profile = nil
 
192
  # db = YAML::Store.new(cache)
 
193
  db = PStore.new(cache)
 
194
  db.transaction do
 
195
    key = service_class.name
 
196
    db[key] ||= {} # initialize db
 
197
    updated = db[key][:updated]
 
198
    if updated && (Time::now < updated + 60 * 60) && db[key][:version] == PROFILE_VERSION
 
199
      # use cache
 
200
      profile = db[key][:profile]
 
201
    else
 
202
      # get latest date and update cache
 
203
      begin
 
204
        profile = service_class.new(id, options)
 
205
      rescue Timeout::Error, StandardError
 
206
        return html << %Q{ <div class="profile">no profile</div> }
 
207
      end
 
208
      db[key][:updated] = Time::now
 
209
      db[key][:profile] = profile
 
210
      db[key][:version] = PROFILE_VERSION
 
211
    end
 
212
  end
 
213
 
 
214
  html << %Q{ <div class="profile"><a href="#{CGI.escapeHTML profile.link}"> }
 
215
  html << %Q{ <span class="profile-image"><img src="#{CGI.escapeHTML profile.image}" alt="profile image"></span> } if profile.image
 
216
  html << %Q{ <span class="profile-name">#{CGI.escapeHTML profile.name}</span> } if profile.name
 
217
  html << %Q{ <span class="profile-mail">#{CGI.escapeHTML profile.mail}</span> } if profile.mail
 
218
  html << %Q{ <span class="profile-description">#{CGI.escapeHTML profile.description}</span> } if profile.description
 
219
  html << %Q{ </a></div> }
 
220
end
 
221