Merge branch 'develop' of git@github.com:Dolibarr/dolibarr.git into develop

This commit is contained in:
Laurent Destailleur 2024-08-17 12:22:45 +02:00
commit 8606175b4e
5 changed files with 204 additions and 30 deletions

View File

@ -68,6 +68,19 @@ if ($action == 'add') {
$socialNetworkName = GETPOST('socialnetwork_name', 'alpha');
$socialNetworkUrl = GETPOST('socialnetwork_url', 'alpha');
// other params if exist
$paramNames = GETPOST('param_name', 'array');
$paramValues = GETPOST('param_value', 'array');
$additionalParams = [];
if (!empty($paramNames) && is_array($paramNames)) {
foreach ($paramNames as $index => $paramName) {
if (!empty($paramName) && isset($paramValues[$index])) {
$additionalParams[$paramName] = $paramValues[$index];
}
}
}
if (!$error) {
$db->begin();
@ -76,6 +89,8 @@ if ($action == 'add') {
'url' => $socialNetworkUrl
);
$socialNetworkData = array_merge($socialNetworkData, $additionalParams);
$boxlabel = '(SocialNetwoksInformations)';
$sql = "INSERT INTO ".MAIN_DB_PREFIX."boxes_def (file, note)";
@ -175,13 +190,37 @@ print '<td>'.$langs->trans('SocialNetworkUrl').'</td>';
print '<td><input type="text" class="flat minwidth300" name="socialnetwork_url"></td>';
print '<td>https://mastodon.social/api/v1/accounts/id_user</td>';
print '</tr>';
print '<tr class="oddeven"><td>';
print $form->textwithpicto($langs->trans("Others"), $langs->trans("AddMoreParams"));
print '</td><td><button type="button" id="addParamButton">'.img_picto($langs->trans("AddMoreParams"), 'add', 'pictofixedwidth').'</button></td>';
print '<td>Token : ****<br>Cookie : ****</td>';
print '</tr>';
print '<tr class="oddeven">';
print '<td colspan="2">';
print '<div id="additionalParams"></div>';
print '</td>';
print '<td></td>';
print '</tr>';
print '</table>';
print '</div>';
print $form->buttonsSaveCancel("Add", '');
print '<input type="hidden" name="action" value="add">';
print '<script type="text/javascript">
document.getElementById("addParamButton").addEventListener("click", function() {
var container = document.getElementById("additionalParams");
var index = container.children.length;
var div = document.createElement("div");
div.className = "pair-group";
div.innerHTML = "<input type=\'text\' class=\'flat minwidth300\' name=\'param_name[]\' placeholder=\''.$langs->trans("ParamName").'\' class=\'flat\' /> <input type=\'text\' class=\'flat minwidth300\' name=\'param_value[]\' placeholder=\''.$langs->trans("ParamValue").'\' class=\'flat\' />";
container.appendChild(div);
});
</script>';
print '</form>';
print '<br><br>';
@ -222,12 +261,20 @@ if ($resql) {
$socialNetworkTitle = $socialNetworkData['title'];
$socialNetworkUrl = $socialNetworkData['url'];
$key = $obj->rowid;
$socialNetworkId = $obj->rowid;
$fediverseparser = new SocialNetworkManager($socialNetworkTitle);
$path_fediverse = DOL_DATA_ROOT.'/fediverse/temp/'.$socialNetworkTitle;
$result = $fediverseparser->fetchPosts($socialNetworkUrl, 5, 300, $path_fediverse);
//check if other params exist
$authParams = [];
foreach ($socialNetworkData as $key => $value) {
if ($key !== 'title' && $key !== 'url') {
$authParams[$key] = $value;
}
}
$result = $fediverseparser->fetchPosts($socialNetworkUrl, 5, 300, $path_fediverse, $authParams);
print "<br>";
print '<form action="'.$_SERVER["PHP_SELF"].'" method="post">'."\n";
@ -238,9 +285,9 @@ if ($resql) {
print '<tr class="liste_titre">';
print "<td>".$langs->trans("SocialNetworks")." ".($i+1)."</td>";
print '<td class="right">';
print '<a class="viewfielda reposition marginleftonly marginrighttonly showInputBtn" href="'.$_SERVER["PHP_SELF"].'?action=editsocialnetwork&token='.newToken().'&key='.urlencode($key).'">'.img_edit().'</a>';
print '<a class="deletefielda reposition marginleftonly right" href="'.$_SERVER["PHP_SELF"].'?action=deletesocialnetwork&token='.newToken().'&key='.urlencode($key).'">'.img_delete().'</a>';
print '<input type="hidden" name="id" value="'.$key.'">';
print '<a class="viewfielda reposition marginleftonly marginrighttonly showInputBtn" href="'.$_SERVER["PHP_SELF"].'?action=editsocialnetwork&token='.newToken().'&key='.urlencode($socialNetworkId).'">'.img_edit().'</a>';
print '<a class="deletefielda reposition marginleftonly right" href="'.$_SERVER["PHP_SELF"].'?action=deletesocialnetwork&token='.newToken().'&key='.urlencode($socialNetworkId).'">'.img_delete().'</a>';
print '<input type="hidden" name="id" value="'.$socialNetworkId.'">';
print '</td>';
print '</tr>'."\n";
@ -271,7 +318,7 @@ if ($resql) {
print '</tr>'."\n";
// Active
$active = _isInBoxListFediverse((int) $key, $boxlist) ? 'yes' : 'no';
$active = _isInBoxListFediverse((int) $socialNetworkId, $boxlist) ? 'yes' : 'no';
print '<tr class="oddeven">';
print '<td>'.$langs->trans('WidgetAvailable').'</td>';

View File

@ -76,11 +76,18 @@ class box_fediverse extends ModeleBoxes
$socialNetworkTitle = '';
$socialNetworkUrl = '';
$authParams = [];
if ($num > 0) {
$obj = $this->db->fetch_row($resql);
$socialNetworkData = json_decode($obj[0], true);
$socialNetworkTitle = $socialNetworkData['title'];
$socialNetworkUrl = $socialNetworkData['url'];
foreach ($socialNetworkData as $key => $value) {
if ($key !== 'title' && $key !== 'url') {
$authParams[$key] = $value;
}
}
}
$fediverseParser = new SocialNetworkManager($socialNetworkTitle);

View File

@ -40,33 +40,111 @@ class MastodonHandler
*/
public $error = '';
/**
* @var string Access token for authenticated requests
*/
private $accessToken;
/**
* fetch Social Network API to retrieve posts.
*
* @param string $urlAPI URL of the Fediverse API.
* @param int $maxNb Maximum number of posts to retrieve (default is 5).
* @param int $cacheDelay Number of seconds to use cached data (0 to disable caching).
* @param string $cacheDir Directory to store cached data.
* @return bool Status code: False if error, true if success.
* @var string The client ID for the Mastodon app
*/
public function fetch($urlAPI, $maxNb = 5, $cacheDelay = 60, $cacheDir = '')
private $clientId;
/**
* @var string The client secret for the Mastodon app
*/
private $clientSecret;
/**
* @var string The redirect URI for the Mastodon app
*/
private $redirectUri;
/**
* Constructor to set the necessary credentials.
*
* @param array $authParams parameters for authentication
*/
public function __construct($authParams)
{
$result = getURLContent($urlAPI, 'GET', '', 1, array(), array('http', 'https'), 0);
if (empty($result['content'])) {
$this->error = 'Error retrieving URL '.$urlAPI;
$this->clientId = $authParams['client_id'] ?? '';
$this->clientSecret = $authParams['client_secret'] ?? '';
$this->redirectUri = $authParams['redirect_uri'] ?? '';
$this->accessToken = $authParams['access_token'] ?? '';
}
/**
* Fetch posts from Mastodon API using the access token.
*
* @param string $urlAPI The URL of the API endpoint
* @param int $maxNb Maximum number of posts to retrieve
* @param int $cacheDelay Cache delay in seconds
* @param string $cacheDir Directory for caching
* @param array $authParams Authentication parameters
* @return array|false Array of posts if successful, False otherwise
*/
public function fetch($urlAPI, $maxNb = 5, $cacheDelay = 60, $cacheDir = '', $authParams = [])
{
if (empty($this->accessToken) && isset($authParams['access_token'])) {
return false;
}
$cacheFile = $cacheDir.'/'.dol_hash($urlAPI, 3);
$foundInCache = false;
$data = null;
$data = json_decode($result['content'], true);
if (!is_array($data)) {
$this->error = 'Invalid JSON format';
return false;
// Check cache
if ($cacheDelay > 0 && $cacheDir && dol_is_file($cacheFile)) {
$fileDate = dol_filemtime($cacheFile);
if ($fileDate >= (dol_now() - $cacheDelay)) {
$foundInCache = true;
$data = file_get_contents($cacheFile);
}
}
$this->posts = array_slice(array_map([$this, 'normalizeData'], $data), 0, $maxNb);
return true;
if (!$foundInCache) {
$headers = [
'Authorization: Bearer ' . $this->accessToken,
'Content-Type: application/json'
];
$result = getURLContent($urlAPI, 'GET', '', 1, $headers, array('http', 'https'), 0);
if (!empty($result['content'])) {
$data = $result['content'];
if ($cacheDir) {
dol_mkdir($cacheDir);
file_put_contents($cacheFile, $data);
}
} else {
$this->error = 'Error retrieving URL ' . $urlAPI;
return false;
}
}
if (!is_null($data)) {
$data = json_decode($data, true);
if (is_array($data)) {
$this->posts = [];
$count = 0;
foreach ($data as $postData) {
if ($count >= $maxNb) {
break;
}
$this->posts[$count] = $this->normalizeData($postData);
$count++;
}
return $this->posts;
} else {
$this->error = 'Invalid data format or empty response';
return false;
}
} else {
$this->error = 'Failed to retrieve or decode data';
return false;
}
}
/**
@ -109,4 +187,40 @@ class MastodonHandler
{
return $this->posts;
}
/**
* Getter for url to redirect
* @return string url
*/
public function getRedirectUri()
{
return $this->redirectUri;
}
/**
* Getter for access token
* @return string token
*/
public function getAccessToken()
{
return $this->accessToken;
}
/**
* Getter for client Id
* @return string client Id
*/
public function getClientId()
{
return $this->clientId;
}
/**
* Getter for secret client
* @return string secret client
*/
public function getClientSecret()
{
return $this->clientSecret;
}
}

View File

@ -59,22 +59,24 @@ class SocialNetworkManager
* Constructor
*
* @param string $platform name of social network
* @param array $authParams other parameters
*/
public function __construct($platform)
public function __construct($platform, $authParams = [])
{
$this->platform = $platform;
$this->initializeHandler();
$this->initializeHandler($authParams);
}
/**
* Initialize the social network needed
* @param array $authParams other parameters
* @return void new instance if founded
*/
private function initializeHandler()
private function initializeHandler($authParams)
{
$handlerClass = dol_ucfirst($this->platform).'Handler';
if (class_exists($handlerClass)) {
$this->handler = new $handlerClass();
$this->handler = new $handlerClass($authParams);
} else {
$this->error = "Handler for $this->platform not found.";
}
@ -87,14 +89,15 @@ class SocialNetworkManager
* @param int $maxNb Maximum number of posts to retrieve (default is 5).
* @param int $cacheDelay Number of seconds to use cached data (0 to disable caching).
* @param string $cacheDir Directory to store cached data.
* @param array $authParams Authentication parameters
* @return bool Status code: false if error, array if success.
*/
public function fetchPosts($urlAPI, $maxNb = 5, $cacheDelay = 60, $cacheDir = '')
public function fetchPosts($urlAPI, $maxNb = 5, $cacheDelay = 60, $cacheDir = '', $authParams = [])
{
if (!$this->handler) {
return false;
}
return $this->handler->fetch($urlAPI, $maxNb, $cacheDelay, $cacheDir);
return $this->handler->fetch($urlAPI, $maxNb, $cacheDelay, $cacheDir, $authParams);
}
/**

View File

@ -2549,3 +2549,6 @@ ConfirmDeleteSocialNetwork= Are you sure want to delete this record ?
AnOwnerMustBeSetIfEmailTemplateIsPrivate=An owner must be set if the email template is set as private
ContactsDefaultRoles=For third parties of the "individual" type, a contact can be created simultaneously. Define here the roles that will be systematically assigned to this contact.
MenuDict=Dictionary
AddMoreParams=Add more parameters for connection (cookies, tokens, ...)<br> Exemple: token : value token
ParamName=Name of parameter
ParamValue=Value of parameter