/
facebook.opa
133 lines (115 loc) · 3.54 KB
/
facebook.opa
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
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
// license: AGPL
// (c) MLstate, 2011, 2012
// author: Adam Koprowski
import stdlib.apis.{facebook, facebook.auth, facebook.graph}
import stdlib.{web.client, system}
// FIXME should be abstract...
type FacebookConnect.user =
{ FbAuth.token token
, string name
}
database Facebook.config /facebook_config
type Facebook.status = {no_credentials}
or {FbAuth.token authenticated}
module FacebookConnect
{
server config =
state = CommandLine.filter(
{ init: none
, parsers: [{ CommandLine.default_parser with
names: ["--fb-config"],
param_doc: "APP_ID,APP_SECRET",
description: "Sets the application ID for the associated Facebook application",
function on_param(state) {
parser {
case app_id=Rule.alphanum_string [,] app_secret=Rule.alphanum_string:
{
fb_config = {~app_id, api_key: app_id, ~app_secret};
// /facebook_config <- fb_config
{no_params: some(fb_config)}
}
}
}
}]
, anonymous: []
, title: "Facebook configuration"
}
)
match (state) {
case {some: config}: config
default:
Log.error("webshell[config]", "Cannot read Facebook configuration (application id and/or secret key)
Please re-run your application with: --fb-config option")
System.exit(1)
}
private FBA = FbAuth(config)
private FBG = FbGraph
private redirect = "http://{Config.host}/connect/facebook"
private function get_fb_name(token) {
opts = { FBG.Read.default_object with token:token.token }
default_name = "<unknown name>"
match (FBG.Read.object("me", opts)) {
case {~object}:
match (List.assoc("name", object.data)) {
case {some: {String: v}}: v
default: default_name
}
default: default_name
}
}
private auth_url = FBA.user_login_url([{publish_stream}], redirect)
xhtml =
<a onclick={function (_) { Client.goto(auth_url) }}>
<img src="resources/img/facebook_signin.png" />
</>
function login(executor)(token) {
function connect(_) {
match (FBA.get_token_raw(token, redirect)) {
case {~token}:
fb_user = { ~token, name: get_fb_name(token) }
Login.set_current_user({~fb_user});
{authenticated: token}
case {error:_}: {no_credentials}
}
}
executor(connect)
}
function get_name(user) {
user.name
}
private function authenticate() {
{ response: {redirect: auth_url},
state_change: {no_change}
}
}
function publish_status(state, status) {
match (state) {
case {authenticated: creds}:
feed = { Facebook.empty_feed with message: status }
outcome = FbGraph.Post.feed(feed, creds.token)
response =
match (outcome) {
case {success:_}: <>Successfully published Facebook feed item: «{feed.message}»</>
case {~error}: <>Error: <b>{error.error}</b>; {error.error_description}</>
}
Service.respond_with(response)
default:
authenticate()
}
}
Service.spec spec =
{ initial_state: Facebook.status {no_credentials},
metadata: {
id: "facebook",
description: "Managing Facebook account",
cmds: [
{ cmd: "fbstatus [content]", description: "Publishes a given Facebook status" }
],
},
function parse_cmd(state) {
parser {
case "fbstatus" Rule.ws content=(.*) : publish_status(state, Text.to_string(content))
}
}
}
}