-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathgithub_connect.module
More file actions
344 lines (291 loc) · 8.77 KB
/
github_connect.module
File metadata and controls
344 lines (291 loc) · 8.77 KB
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
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
<?php
/**
* @file
* Gives site visitors the ability to log in with GitHub (http://github.com).
*/
/**
* Implements hook_help().
*/
function github_connect_help($path, $arg) {
switch ($path) {
case 'admin/config/people/github':
return t('Gives site visitors the ability to login to Drupal with their GitHub account.');
}
}
/**
* Implements hook_block_info().
*/
function github_connect_block_info() {
$blocks['github_connect-login'] = array(
'info' => t('Github connect'),
);
return $blocks;
}
/**
* Implements hook_block_view().
*/
function github_connect_block_view($delta = '') {
$block = array();
switch ($delta) {
case 'github_connect-login':
return array(
'subject' => '',
'content' => github_connect_connect_block(),
);
break;
}
return $block;
}
/**
* GitHub connect block.
*/
function github_connect_connect_block() {
if (user_is_logged_in()) return FALSE;
$client_id = variable_get('github_connect_client_id');
$link = 'https://github.com/login/oauth/authorize?client_id=' . $client_id;
$output = l(t('Login with GitHub'), $link);
return $output;
}
/*
* Implements hook_menu().
*/
function github_connect_menu() {
// Admin settings page.
$items['admin/config/people/github'] = array(
'title' => 'Github settings',
'description' => 'Settings for connecting with Github.',
'page callback' => 'drupal_get_form',
'page arguments' => array('github_connect_admin_settings_form'),
'access arguments' => array('administer github_connect'),
'type' => MENU_NORMAL_ITEM,
'file' => 'github_connect.admin.inc',
);
// Callback for oauth token request from Github API.
$items['github/register/create'] = array(
'type' => MENU_CALLBACK,
'title' => 'Connected to Github',
'page callback' => 'github_connect_get_access_token',
'access callback' => 'user_is_anonymous',
// 'file' => 'github_connect.pages.inc',
);
// Require password when merging accounts
$items['github/verify/email/%/%'] = array(
'type' => MENU_CALLBACK,
'title' => 'Merge accounts',
'page callback' => 'drupal_get_form',
'page arguments' => array('github_connect_verify_email_form', 3, 4),
'access callback' => TRUE,
);
return $items;
}
/**
* Implements hook_user_delete().
*/
function github_connect_user_delete($account) {
// Delete the user from github_connect_users table.
if (github_connect_get_user_token($account->uid)) {
db_delete('github_connect_users')
->condition('uid', $account->uid)
->execute();
}
}
/*
* Custom access callback.
*/
function github_connect_get_access_token() {
$client_id = variable_get('github_connect_client_id');
$client_secret = variable_get('github_connect_client_secret');
// The response code after first call to GitHub.
$code = $_GET['code'];
$url = 'https://github.com/login/oauth/access_token?';
$options = array(
'data' => 'client_id=' . $client_id . '&client_secret=' . $client_secret . '&code=' . $code,
'method' => 'POST',
);
$response = drupal_http_request($url, $options);
$token = $response->data;
if ($token) {
// Check if a user exists for the token.
$uid = github_connect_get_token_user($token);
if (!empty($uid)) {
// If there is a user with the token log that user in.
$form_state['uid'] = $uid;
user_login_submit(array(), $form_state);
drupal_goto();
return;
}
else {
// Collects the User information from GitHub.
$options = array(
'method' => 'GET',
'timeout' => 7200,
);
$github_user = drupal_http_request('https://api.github.com/user?' . $token, $options);
$ghuser = drupal_json_decode($github_user->data);
if ($ghuser['email']) {
$existing_user = user_load_by_mail($ghuser['email']);
if ($existing_user) {
drupal_goto('github/verify/email/' . $existing_user->uid . '/' . $token);
}
else {
_github_connect_register($ghuser, $token);
}
}
else {
drupal_set_message(t('We could not log you in due to an error accessing your GitHub account.'), 'error');
return;
}
}
}
else {
drupal_set_message(t('Failed connecting to GitHub.'), 'error');
}
}
/*
* Save the new GitHub user in github_connect_users
*/
function _github_connect_save_github_user($account, $token) {
// Store GitHub user with token.
if ($account) {
db_insert('github_connect_users')
->fields(array(
'uid' => $account->uid,
'access_token' => $token,
'timestamp' => REQUEST_TIME,
))
->execute();
// Log in the stored user.
$form_state['uid'] = $account->uid;
user_login_submit(array(), $form_state);
drupal_set_message(t('You are now connected with your GitHub account.'));
drupal_goto();
}
}
/*
* Register new user.
*/
function _github_connect_register($ghuser, $token) {
$username = $ghuser['login'];
// Check if username exists and assign a new username.
// @TODO If username already exists the user should be able to pick a new one.
// @TODO User should be notified that he has been assigned a new username.
if (_github_connect_username_stored($username)) {
$i = 1;
do {
if (_github_connect_username_stored($username . $i)) {
$i++;
}
elseif ($i === 10) {
drupal_set_message(t('Error connecting account. A username could not be generated.'), 'error');
return;
}
else {
// If availible the user will be given $username_[number].
$username = $username . '_' . $i;
break;
}
}
// Limit to 10.
while ($i <= 10);
}
$userinfo = array(
'name' => $username,
'mail' => $ghuser['email'],
'pass' => user_password(),
'status' => 1,
'access' => REQUEST_TIME,
'init' => $ghuser['email'],
);
$account = user_save('', $userinfo);
if ($account) {
_github_connect_save_github_user($account, $token);
}
else {
drupal_set_message(t('Error saving new user.'), 'error');
return;
}
}
/**
* Check to see if username is already stored
*/
function _github_connect_username_stored($name) {
$query = db_select('users', 'u');
$query->fields('u', array('uid'));
$query->condition('name', $name, '=');
return $query->execute()->fetchField();
}
/**
* Require user to verify email address when merging accounts.
*/
function github_connect_verify_email_form($form, &$form_state, $uid, $token) {
$account = user_load($uid);
$form['message'] = array(
'#type' => 'item',
'#title' => t('Email address in use'),
'#markup' => t('There is already an account associated with your GitHub email address. Type your !site account password to merge accounts.', array('!site' => variable_get('site_name'))),
);
$form['name'] = array('#type' => 'hidden', '#value' => $account->name);
$form['pass'] = array('#type' => 'password',
'#title' => t('Password'),
'#description' => t('Enter your password.'),
'#required' => TRUE,
);
$form['token'] = array('#type' => 'hidden', '#value' => $token);
$form['actions'] = array('#type' => 'actions');
$form['actions']['submit'] = array('#type' => 'submit', '#value' => t('Merge accounts'));
$form['#validate'] = array('github_connect_verify_email_form_validate');
$form['#submit'] = array('github_connect_verify_email_form_submit');
return $form;
}
/**
* Validation to check correct password when merging.
*/
function github_connect_verify_email_form_validate($form, &$form_state) {
$name = $form_state['values']['name'];
$password = $form_state['values']['pass'];
if (user_authenticate($name, $password) == FALSE) {
form_set_error('pass', t('Incorrect password.'));
}
}
/**
* Custom submit function to save user when merging.
*/
function github_connect_verify_email_form_submit($form, &$form_state) {
$account = user_load_by_name($form_state['values']['name']);
$token = $form_state['values']['token'];
_github_connect_save_github_user($account, $token);
}
/**
* Get User id from GitHub access token
*
* @param $token Access token from GitHub
* @return $uid Drupal user id
*/
function github_connect_get_token_user($token) {
if ($token) {
$result = db_select('github_connect_users', 'g_u')
->fields('g_u', array('uid', 'access_token'))
->condition('access_token', $token, '=')
->execute()
->fetchAssoc();
$uid = $result['uid'];
return $uid;
}
}
/**
* Get GitHub access token for User
*
* @param $uid User user id
* @return $token Access token from GitHub
*/
function github_connect_get_user_token($uid) {
if ($uid) {
$result = db_select('github_connect_users', 'g_u')
->fields('g_u', array('uid', 'access_token'))
->condition('uid', $uid, '=')
->execute()
->fetchAssoc();
$token = $result['access_token'];
return $token;
}
}