Merge lp:~sergiusens/account-polld/twitter_avatar into lp:~phablet-team/account-polld/trunk

Proposed by Sergio Schvezov
Status: Merged
Approved by: Sergio Schvezov
Approved revision: 25
Merged at revision: 24
Proposed branch: lp:~sergiusens/account-polld/twitter_avatar
Merge into: lp:~phablet-team/account-polld/trunk
Prerequisite: lp:~sergiusens/account-polld/google_credentials
Diff against target: 135 lines (+70/-3)
2 files modified
plugins/plugins.go (+56/-0)
plugins/twitter/twitter.go (+14/-3)
To merge this branch: bzr merge lp:~sergiusens/account-polld/twitter_avatar
Reviewer Review Type Date Requested Status
PS Jenkins bot continuous-integration Approve
Roberto Alsina (community) Approve
Manuel de la Peña Pending
Review via email: mp+228405@code.launchpad.net

Commit message

If the twitter user's avatar is available use it in the notification card's icon

To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
25. By Sergio Schvezov

Download into cache instead and make DownloadAvatar worth it's name.

Revision history for this message
Roberto Alsina (ralsina) wrote :

Other than the inline comment which is just a doubt, +1

review: Approve
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Sergio Schvezov (sergiusens) wrote :

On sábado 26 de julio de 2014 18h'17:55 ART, Roberto Alsina wrote:
> Review: Approve
>
> Other than the inline comment which is just a doubt, +1
>
> Diff comments:
>
>> === modified file 'plugins/plugins.go'
>> --- plugins/plugins.go 2014-07-25 20:09:20 +0000
>> +++ plugins/plugins.go 2014-07-26 21:03:48 +0000
>> @@ -19,10 +19,20 @@
>>
>> import (
> ...
>
> I keep getting confused as to whether to return err, result or
> result, err in go.
> If we want to check the error, it makes sense to return error
> first so it's harder to ignore.

By convention errors are the last return value.
I can't ignore it either unless I ignore everything or ignore it explicitly
as seen here:
http://play.golang.org/p/6kCrwVCzEt

>
>> + filePart := filepath.Join(cmdName, "avatars", pluginName,
>> path.Base(url))
>> + if file, err := xdg.Cache.Find(filePart); err == nil {
>> + return file, nil
>> + }
>> +
> ...
>
>

Revision history for this message
James Henstridge (jamesh) wrote :

Is it possible to pass the HTTP URL as part of the notification rather than downloading the image explicitly? There is already efforts to add a disk cache for downloaded images to the shell, so do we need a separate one here?

Revision history for this message
Sergio Schvezov (sergiusens) wrote :

On lunes 28 de julio de 2014 04h'33:13 ART, James Henstridge wrote:
> Is it possible to pass the HTTP URL as part of the notification
> rather than downloading the image explicitly? There is already
> efforts to add a disk cache for downloaded images to the shell,
> so do we need a separate one here?

This will need to be circled back to the push people, AFAIK, that is not
yet supported.

Revision history for this message
Sergio Schvezov (sergiusens) wrote :

On lunes 28 de julio de 2014 09h'03:21 ART, Sergio Schvezov wrote:
> On lunes 28 de julio de 2014 04h'33:13 ART, James Henstridge wrote:
>> Is it possible to pass the HTTP URL as part of the notification
>> rather than downloading the image explicitly? There is already
>> efforts to add a disk cache for downloaded images to the shell,
>> so do we need a separate one here?
>
> This will need to be circled back to the push people, AFAIK, that is not
> yet supported.

Just tried (with gdbus), it does't work.

Revision history for this message
James Henstridge (jamesh) wrote :

My main concerns with this are:

1. there is no cache eviction, so it will continue to grow unchecked. There is nothing in the push notifications model to tell account-polld when the image isn't needed any more either, so it's not clear how this can be handled reliably.

2. there is no cache validation, so if new avatar images are served from the same URL we will never notice that change.

And if using URIs for icons doesn't work, how exactly will real push notifications provide icons once we have them?

Revision history for this message
Sergio Schvezov (sergiusens) wrote :

On martes 29 de julio de 2014 00h'47:50 ART, James Henstridge wrote:
> My main concerns with this are:
>
> 1. there is no cache eviction, so it will continue to grow
> unchecked. There is nothing in the push notifications model to
> tell account-polld when the image isn't needed any more either,
> so it's not clear how this can be handled reliably.
>
> 2. there is no cache validation, so if new avatar images are
> served from the same URL we will never notice that change.

I thought of adding this as a next step.

> And if using URIs for icons doesn't work, how exactly will real
> push notifications provide icons once we have them?

Chipaca told me that the push-helper would do that.

Revision history for this message
James Henstridge (jamesh) wrote :

That still doesn't answer the question of how account-polld will know when a particular image is no longer needed. The post office never tells us when a particular notification has been dismissed. The more I think about it, the more this feels like the wrong way to handle the problem.

Revision history for this message
Sergio Schvezov (sergiusens) wrote :

On martes 29 de julio de 2014 07h'28:43 ART, James Henstridge wrote:
> That still doesn't answer the question of how account-polld
> will know when a particular image is no longer needed. The post
> office never tells us when a particular notification has been
> dismissed. The more I think about it, the more this feels like
> the wrong way to handle the problem.

Feel free to rewrite it. I just downloaded persistently to keep it on
across reboots since my gripe with the unity click scope making me spend
more money than I wanted to.

Does it matter for account-polld to know the instant it doesn't need an
image anymore? I'd believe mentions are from the same regular people most
of the time.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'plugins/plugins.go'
--- plugins/plugins.go 2014-07-25 20:09:20 +0000
+++ plugins/plugins.go 2014-07-26 21:03:48 +0000
@@ -19,10 +19,20 @@
1919
20import (20import (
21 "errors"21 "errors"
22 "io"
23 "net/http"
24 "os"
25 "path"
26 "path/filepath"
2227
23 "launchpad.net/account-polld/accounts"28 "launchpad.net/account-polld/accounts"
29 "launchpad.net/go-xdg/v0"
24)30)
2531
32func init() {
33 cmdName = os.Args[0]
34}
35
26// Plugin is an interface which the plugins will adhere to for the poll36// Plugin is an interface which the plugins will adhere to for the poll
27// daemon to interact with.37// daemon to interact with.
28//38//
@@ -131,6 +141,8 @@
131// the web service reported that the authentication token has expired.141// the web service reported that the authentication token has expired.
132var ErrTokenExpired = errors.New("Token expired")142var ErrTokenExpired = errors.New("Token expired")
133143
144var cmdName string
145
134// DefaultSound returns the path to the default sound for a Notification146// DefaultSound returns the path to the default sound for a Notification
135func DefaultSound() string {147func DefaultSound() string {
136 return "/usr/share/sounds/ubuntu/notifications/Slick.ogg"148 return "/usr/share/sounds/ubuntu/notifications/Slick.ogg"
@@ -140,3 +152,47 @@
140func DefaultVibration() *Vibrate {152func DefaultVibration() *Vibrate {
141 return &Vibrate{Duration: 200}153 return &Vibrate{Duration: 200}
142}154}
155
156func DownloadAvatar(pluginName, url string) (string, error) {
157 filePart := filepath.Join(cmdName, "avatars", pluginName, path.Base(url))
158 if file, err := xdg.Cache.Find(filePart); err == nil {
159 return file, nil
160 }
161
162 file, err := xdg.Cache.Ensure(filePart)
163 if err != nil {
164 return "", err
165 }
166
167 if err := download(file, url); err != nil {
168 return "", err
169 }
170
171 return file, nil
172}
173
174func download(file, url string) (err error) {
175 defer func() {
176 if err != nil {
177 os.Remove(file)
178 }
179 }()
180
181 out, err := os.Create(file)
182 if err != nil {
183 return err
184 }
185 defer out.Close()
186
187 resp, err := http.Get(url)
188 if err != nil {
189 return err
190 }
191 defer resp.Body.Close()
192
193 if _, err := io.Copy(out, resp.Body); err != nil {
194 return err
195 }
196
197 return nil
198}
143199
=== modified file 'plugins/twitter/twitter.go'
--- plugins/twitter/twitter.go 2014-07-25 19:01:28 +0000
+++ plugins/twitter/twitter.go 2014-07-26 21:03:48 +0000
@@ -32,7 +32,10 @@
3232
33var baseUrl, _ = url.Parse("https://api.twitter.com/1.1/")33var baseUrl, _ = url.Parse("https://api.twitter.com/1.1/")
3434
35const twitterIcon = "/usr/share/click/preinstalled/.click/users/@all/com.ubuntu.developer.webapps.webapp-twitter/twitter.png"35const (
36 twitterIcon = "/usr/share/click/preinstalled/.click/users/@all/com.ubuntu.developer.webapps.webapp-twitter/twitter.png"
37 pluginName = "twitter"
38)
3639
37const (40const (
38 maxIndividualStatuses = 241 maxIndividualStatuses = 2
@@ -107,13 +110,17 @@
107110
108 pushMsg := []plugins.PushMessage{}111 pushMsg := []plugins.PushMessage{}
109 for _, s := range statuses {112 for _, s := range statuses {
113 icon, err := plugins.DownloadAvatar(pluginName, s.User.Image)
114 if err != nil {
115 icon = twitterIcon
116 }
110 pushMsg = append(pushMsg, plugins.PushMessage{117 pushMsg = append(pushMsg, plugins.PushMessage{
111 Notification: plugins.Notification{118 Notification: plugins.Notification{
112 Card: &plugins.Card{119 Card: &plugins.Card{
113 Summary: fmt.Sprintf("@%s mentioned you", s.User.ScreenName),120 Summary: fmt.Sprintf("@%s mentioned you", s.User.ScreenName),
114 Body: s.Text,121 Body: s.Text,
115 Actions: []string{fmt.Sprintf("http://mobile.twitter.com/%s/statuses/%d", s.User.ScreenName, s.Id)},122 Actions: []string{fmt.Sprintf("http://mobile.twitter.com/%s/statuses/%d", s.User.ScreenName, s.Id)},
116 Icon: twitterIcon,123 Icon: icon,
117 Persist: true,124 Persist: true,
118 Popup: true,125 Popup: true,
119 },126 },
@@ -180,13 +187,17 @@
180187
181 pushMsg := []plugins.PushMessage{}188 pushMsg := []plugins.PushMessage{}
182 for _, m := range dms {189 for _, m := range dms {
190 icon, err := plugins.DownloadAvatar(pluginName, m.Sender.Image)
191 if err != nil {
192 icon = twitterIcon
193 }
183 pushMsg = append(pushMsg, plugins.PushMessage{194 pushMsg = append(pushMsg, plugins.PushMessage{
184 Notification: plugins.Notification{195 Notification: plugins.Notification{
185 Card: &plugins.Card{196 Card: &plugins.Card{
186 Summary: fmt.Sprintf("@%s sent you a DM", m.Sender.ScreenName),197 Summary: fmt.Sprintf("@%s sent you a DM", m.Sender.ScreenName),
187 Body: m.Text,198 Body: m.Text,
188 Actions: []string{fmt.Sprintf("http://mobile.twitter.com/%s/messages", m.Sender.ScreenName)},199 Actions: []string{fmt.Sprintf("http://mobile.twitter.com/%s/messages", m.Sender.ScreenName)},
189 Icon: twitterIcon,200 Icon: icon,
190 Persist: true,201 Persist: true,
191 Popup: true,202 Popup: true,
192 },203 },

Subscribers

People subscribed via source and target branches