[Tiki-devel] Social Libs and logins revamp
Arijus Bernotas via TikiWiki-devel <[email protected]>
| Newsgroups | gmane.comp.cms.tiki.devel |
|---|---|
| Message-ID | <[email protected]> |
Hi all fantastic people,
After some struggle with hybridauth (to make it work with tiki -
practically I had to fork it) I switched to phpleague and made it work
easily. But the current tiki code structure for social logins forces to
create different files in the root of tiki for each social network which
can grow to hundreds or thousands. e.g tiki-socialnetworks-facebook.php etc.
So,
Q1: First of all, do we need all kind SocialLib extends LogsLibs?
Q2: Or is better class TikiFacebook extends TikiSocial or it would be
even possible to have one TikiSocial class and construct an instance by
sending config params accordingly to each socnetwork?
Q3: Is it better to create a separate folder/s for socnetworks and/or
their logins? If yes , then where?
Please have in mind that I have strong C++ paradigms in mind... :)
P.S. I hope to have working public demo very soon again because my eu
domain after brexit stopped working...
Aris
Below is the code which I hope still works with phpleague and my forked
hybridauth (some commented parts) (needs changed parts )
<?php
// (c) Copyright by authors of the Tiki Wiki CMS Groupware Project
//
// All Rights Reserved. See copyright.txt for details and a complete
list of authors.
// Licensed under the GNU LESSER GENERAL PUBLIC LICENSE. See license.txt
for details.
// $Id: tikifacebooklib.php 2019-12-08 aris002
// this script may only be included - so its better to die if called
directly.
if (strpos($_SERVER['SCRIPT_NAME'], basename(__FILE__)) !== false) {
header('location: index.php');
exit;
}
$logslib = TikiLib::lib('logs');
//Feedback::warning(tr('start tikifacebooklib'));
/**
* This class serves facebook login into tiki functions
* Is it better to name it TikiFacebookLib or just TikiFacebook?
* @author aris002 and others. Please add yourself if you see your code...
*/
class TikiFacebookLib extends LogsLib
{
private $graphVersion = 'v3.2'; //we can set it in preferences as well?
private $config3; //ending with "3" to remind us that the
structures come from the third party. In this case - thephpleague.
private $provider3;
private $profile3;
private $access_token;
public function __construct()
{
global $prefs;
if (! $this->isFacebookRegistered()) {
Feedback::error(tr('this site is not registered with
Facebook!'));
// do we need to land on tiki-admin.php?
header('Location: tiki-index.php');
die();
}
$this->config3 = [
'clientId' =>
$prefs['socialnetworks_facebook_application_id'],
'clientSecret' =>
$prefs['socialnetworks_facebook_application_secr'],
'redirectUri' => $this->getURL(),
'graphApiVersion' => $this->graphVersion,
];
$this->provider3 = new
\League\OAuth2\Client\Provider\Facebook($this->config3);
}
/**
* retrieves the URL for the current page
*
* @return string URL for the current page
*/
function getURL()
{
$url = 'http';
$port = '';
if (! empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') {
$url .= 's';
if ($_SERVER['SERVER_PORT'] != 443 and
strpos($_SERVER['HTTP_HOST'], ':') == 0) {
$port = ':' . $_SERVER['SERVER_PORT'];
}
} else {
if ($_SERVER['SERVER_PORT'] != 80 and
strpos($_SERVER['HTTP_HOST'], ':') == 0) {
$port = ':' . $_SERVER['SERVER_PORT'];
}
}
$url .= '://' . $_SERVER['HTTP_HOST'] . $port .
$_SERVER['REQUEST_URI'];
// Feedback::warning('inside tikifacebooklib getURL()=' . $url);
return $url;
}
/**
* Checks if the site is registered with facebook (application id ,
api key and secret are set)
*
* @return bool true, if this site is registered with facebook
as an application
*/
function isFacebookRegistered()
{
global $prefs;
return ($prefs['socialnetworks_facebook_application_id'] != ''
and $prefs['socialnetworks_facebook_application_secr'] != '');
}
/**
* Partial login into tiki - tries to connect with facebook and to
retrieve user's facebook profile
*
* @return bool true, if login with facebook and user profile is ok
*/
function loginPre()
{
global $prefs, $user;
try {
$this->getAccessToken();
$fb_profile =
$this->provider3->getResourceOwner($this->access_token);
}
catch (\Exception $e) {
Feedback::error(tr('Oops! We ran into an unknown issue:
'.$e->getMessage() ));
}
if ( is_object($fb_profile) && ! empty(
$fb_profile->getId() ) )
{
$this->loginMain($access_token, $fb_profile);
}
// elseif (is_object($fb_profile) &&
is_object($fb_profile->error)) //do we need more precise errors?
// {
// Feedback::error($fb_profile->error->type . ': ' .
$fb_profile->error->message);
// return false;
// }
else
{
Feedback::error(tr('Oops! Facebook profile information
has not been retrieved!'));
return false;
}
return true;
}
/**
* @return Facebook access token, if all is ok
*/
function getAccessToken()
{
$this->access_token =
$this->provider3->getAccessToken('authorization_code', [ 'code' =>
$_GET['code'] ] );
return $this->access_token;
}
/**
* This is where a real login with access_token and facebook profile
fb_profile into your tiki happens
* @return bool true, if all is ok
*/
function loginMain($access_token, $fb_profile)
{
global $prefs, $user;
$userlib = TikiLib::lib('user');
// $fid = $fb_profile->id;
$fb_id = $fb_profile->getId();
// Feedback::warning("fid" . ': ' . $fb_id);
if (! $user) {
if ($prefs['socialnetworks_facebook_login'] != 'y') {
return false;
}
// $local_user = $this->getOne("select `user` from
`tiki_user_preferences` where `prefName` = 'facebook_id' and `value` =
?", [$fb_profile->id]);
$local_user = $this->getOne("select `user` from
`tiki_user_preferences` where `prefName` = 'facebook_id' and `value` =
?", [$fb_id]);
// Feedback::warning("local_user" . ': ' . $local_user);
if ($local_user) {
$user = $local_user;
} elseif ($prefs['socialnetworks_facebook_autocreateuser']
== 'y') {
$local_user = $this->createUser($access_token,
$fb_profile);
}
if ($local_user) {
$user = $local_user;
} else {
$smarty = TikiLib::lib('smarty');
$smarty->assign('errortype', 'login');
$smarty->assign('msg', tra('You need to link your local
account to Facebook before you can login using it'));
$smarty->display('error.tpl');
die;
}
global $user_cookie_site;
$_SESSION[$user_cookie_site] = $user;
$userlib->update_expired_groups();
$this->set_user_preference($user, 'facebook_id', $fb_id);
$this->set_user_preference($user, 'facebook_token',
$access_token);
$userlib->update_lastlogin($user);
header('Location: tiki-index.php');
die;
} else { //relogin if logged in?
$this->set_user_preference($user, 'facebook_id', $fb_id);
$this->set_user_preference($user, 'facebook_token',
$access_token);
}
return true; //do we need this?
}
/**
* if this site is registered with facebook, it redirects to
facebook to ask for a request token
*
*/
function requestAuthorization()
{
global $prefs;
$scopes = [];
// if ($prefs['socialnetworks_facebook_publish_stream'] == 'y') {
// $scopes[] = 'publish_actions';
// }
if ($prefs['socialnetworks_facebook_manage_events'] == 'y') {
$scopes[] = 'create_event';
$scopes[] = 'rsvp_event';
}
if ($prefs['socialnetworks_facebook_sms'] == 'y') {
$scopes[] = 'sms';
}
if ($prefs['socialnetworks_facebook_manage_pages'] == 'y') {
$scopes[] = 'manage_pages';
}
if ($prefs['socialnetworks_facebook_email'] === 'y') {
$scopes[] = 'email';
}
$scope = implode(',', $scopes);
$url = $this->getURL();
if (strpos($url, '?') != 0) {
$url = preg_replace('/\?.*/', '', $url);
}
$url = urlencode($url . '?request_facebook');
$url = 'https://www.facebook.com/' . $this->graphVersion .
'/dialog/oauth?client_id='
. $prefs['socialnetworks_facebook_application_id'] .
'&scope=' . $scope . '&redirect_uri=' . $url;
// Feedback::warning(tr('inside tikifacebooklib
requestAuthorization'));
header("Location: $url");
die();
}
/**
* Creates a new tiki user from a facebook profile
*
* @returns $user it created
*/
function createUser($access_token, $fb_profile)
{
global $prefs, $user;
$userlib = TikiLib::lib('user');
$randompass = $userlib->genPass();
$email = $prefs['socialnetworks_facebook_email'] === 'y' ?
$fb_profile->email : '';
if ($prefs['login_is_email'] == 'y' && $email) {
$user = $email;
} elseif ($prefs['login_autogenerate'] == 'y') {
$user = '';
} else {
$user = 'fb_' . $fb_profile->id;
}
$user = $userlib->add_user($user, $randompass, $email);
if (! $user) {
$smarty = TikiLib::lib('smarty');
$smarty->assign('errortype', 'login');
$smarty->assign('msg', tra('We were unable to create a new
user with your Facebook account. Please contact the administrator.'));
$smarty->display('error.tpl');
die;
}
$ret = $userlib->get_usertrackerid("Registered");
$userTracker = $ret['usersTrackerId'];
$userField = $ret['usersFieldId'];
if ($prefs['socialnetworks_facebook_create_user_trackeritem']
== 'y' && $userTracker && $userField) {
$definition = Tracker_Definition::get($userTracker);
$utilities = new Services_Tracker_Utilities();
$fields = ['ins_' . $userField => $user];
if (! empty($prefs['socialnetworks_facebook_names'])) {
$names = array_map('trim', explode(',',
$prefs['socialnetworks_facebook_names']));
$fields['ins_' . $names[0]] = $fb_profile->first_name;
$fields['ins_' . $names[1]] = $fb_profile->last_name;
}
$utilities->insertItem(
$definition,
[
'status' => '',
'fields' => $fields,
'validate' => false,
]
);
}
$this->set_user_preference($user, 'realName', $fb_profile->name);
if ($prefs['socialnetworks_facebook_firstloginpopup'] == 'y') {
$this->set_user_preference($user,
'socialnetworks_user_firstlogin', 'y');
}
if ($prefs['feature_userPreferences'] == 'y') {
$fb_avatar = json_decode($this->facebookGraph('',
'me/picture', ['type' => 'square', 'width' => '480', 'redirect' =>
'0','access_token' => $access_token], false, 'GET'));
$avatarlib = TikiLib::lib('avatar');
$avatarlib->set_avatar_from_url($fb_avatar->data->url, $user);
}
return $user;
}
/**
* Do we still need this?
* Talking to Facebook via the graph api at
"https://graph.facebook.com/" using fsockopen
*
* @param string $user userId of the user to send the
request for
* @param string $action directory/file part of the graph api URL
* @param array $params parameters for the api call, each
entry is one element submitted in the request
* @param bool $addtoken should the access token be added to
the parameters if the calling function did not pass this parameter
*
* @param string $method
*
* @return string body of the response page (json
encoded object)
* @throws Exception
*/
function facebookGraph($user, $action, $params, $addtoken = true,
$method = 'POST')
{
if (! $this->facebookRegistered()) {
$this->add_log('facebookGraph', 'application not set up');
return false;
}
if ($addtoken) {
$token = $this->get_user_preference($user,
'facebook_token', '');
if ($token == '') {
$this->add_log('facebookGraph', 'user not registered
with facebook');
return false;
}
if (! isset($params['access_token'])) {
$params['access_token'] = $token;
}
}
// set up http client to make request
$url = 'https://graph.facebook.com/' . $this->graphVersion .
'/' . $action;
if (! empty($params) && is_array($params) && $method === 'GET') {
// set url this way instead of using setUri and
setParameterGet to avoid failure in some environments
$url .= '?' . urldecode(http_build_query($params, '', '&'));
}
$client = TikiLib::lib('tiki')->get_http_client($url);
$client->setMethod($method);
if (! empty($params) && is_array($params) && $method === 'POST') {
$client->setParameterPost($params);
}
// make request
$response = $client->send();
return $response->getBody();
}
/**
*
* publish a message (status or link with more options) on facebook
*
* @param string $user userId of the user to send for
* @param string $message message/main text to send
* @param string $url optional URL to pass along
* @param string $text optional text to show for the URL
* @param string $caption optional caption of the message
accompanying the url
* @param string $privacy currently unused as I did not find
the docu on how to use the privacy settings
*
* @return string|bool false on error, object Id of
the message on success
*/
function facebookWallPublish($user, $message, $url = '', $text =
'', $caption = '', $privacy = '')
{
$params = [];
if ($url != '') {
$params['link'] = $url;
if ($text != '') {
$params['name'] = $text;
}
if ($caption != '') {
$params['caption'] = $caption;
}
$params['description'] = $message;
} else {
$params['message'] = substr($message, 0, 400);
}
$ret = $this->facebookGraph($user, 'me/feed/', $params);
$result = json_decode($ret);
if (isset($result->id)) {
return $result->id;
} else {
return false;
}
}
/**
* like an object on facebook
*
* @param string $user userId of the user to send for
* @param string $facebookId id of the object to like
*
* @return string|bool false on error, object Id of
the message on success
*/
function facebookLike($user, $id)
{
$params = [];
$ret = $this->facebookGraph($user, "$id/likes/", $params);
return json_decode($ret);
}
/**
* TODO Use something from phpLeague or remove?
*/
function getFacebookUserProfile($access_token)
{
global $prefs;
$fields = ['id', 'name', 'first_name', 'last_name'];
if ($prefs['socialnetworks_facebook_email'] == 'y') {
$fields[] = 'email';
}
$resp = $this->facebookGraph('', 'me', ['fields' =>
implode(',', $fields),'access_token' => $access_token], false, 'GET');
$fb_profile = json_decode($resp);
return $fb_profile;
}
}
global $tikifacebooklib;
$tikifacebooklib = new TikiFacebookLib();
_______________________________________________
TikiWiki-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/tikiwiki-devel