forked from rainycape/gondola
/
facebook.go
115 lines (103 loc) · 3.05 KB
/
facebook.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
package users
import (
"fmt"
"net/url"
"reflect"
"time"
"gondola/app"
"gondola/net/oauth2"
"gondola/social/facebook"
)
type Facebook struct {
Id string `form:"-" sql:",unique" json:"id"`
Username string `form:"-" json:"username"`
Name string `form:"-" json:"name"`
FirstName string `form:"-" json:"first_name"`
LastName string `form:"-" json:"last_name"`
Email string `form:"-" json:"email"`
Image string `form:"-" json:"-"`
ImageFormat string `form:"-" json:"-"`
ImageURL string `form:"-" json:"-"`
Token string `form:"-" json:"-"`
Expires time.Time `form:"-" json:"-"`
}
func (f *Facebook) accountId() interface{} {
return f.Id
}
func (f *Facebook) imageURL() string {
return f.ImageURL
}
func (f *Facebook) username() string {
if f.Username != "" {
return f.Username
}
return f.FirstName
}
func (f *Facebook) email() string {
return f.Email
}
func signInFacebookTokenHandler(ctx *app.Context, client *oauth2.Client, token *oauth2.Token) {
user, err := userFromFacebookToken(ctx, token)
if err != nil {
panic(err)
}
ctx.MustSignIn(asGondolaUser(user))
redirectToFrom(ctx)
}
func jsSignInFacebookHandler(ctx *app.Context) {
req := ctx.FormValue("req")
fbApp := data(ctx).opts.FacebookApp.Clone(ctx)
resp, err := fbApp.ParseSignedRequest(req)
if err != nil {
panic(err)
}
// Let it crash if the data does not have the
// specified format, this will make it easier
// to find it if it happens.
code := resp["code"].(string)
token, err := fbApp.Exchange("", code)
user, err := userFromFacebookToken(ctx, token)
if err != nil {
panic(err)
}
ctx.MustSignIn(asGondolaUser(user))
writeJSONEncoded(ctx, user)
}
func fetchFacebookUser(ctx *app.Context, token *oauth2.Token) (*Facebook, error) {
fields := "id,name,first_name,last_name,email,username,picture.width(200),picture.height(200)"
values := make(url.Values)
values.Set("fields", fields)
fbApp := data(ctx).opts.FacebookApp.Clone(ctx)
var person *facebook.Person
if err := fbApp.Get("/me", values, token.Key, &person); err != nil {
return nil, err
}
var imageURL string
if person.Picture != nil && person.Picture.Data != nil && !person.Picture.Data.IsSilhouette {
imageURL = person.Picture.Data.URL
}
return &Facebook{
Id: person.Id,
Username: person.Username,
Name: person.Name,
FirstName: person.FirstName,
LastName: person.LastName,
Email: person.Email,
ImageURL: imageURL,
Token: token.Key,
Expires: token.Expires.UTC(),
}, nil
}
func userFromFacebookToken(ctx *app.Context, token *oauth2.Token) (reflect.Value, error) {
fbApp := data(ctx).opts.FacebookApp.Clone(ctx)
extended, err := fbApp.Clone(ctx).Extend(token)
if err != nil {
return reflect.Value{}, err
}
user, err := fetchFacebookUser(ctx, extended)
return userWithSocialAccount(ctx, SocialAccountTypeFacebook, user)
}
func FacebookChannelHandler(ctx *app.Context) {
ctx.Header().Set("Content-Type", "text/html")
fmt.Fprintf(ctx, "<script src=\"//connect.facebook.net/en_US/all.js\"></script>")
}