Adding to SP3 : fixing images and others

This commit is contained in:
2014-11-30 17:24:49 +01:00
parent b6ebf33a02
commit c1f4308089
9 changed files with 159 additions and 115 deletions

View File

@@ -512,28 +512,38 @@ class Databap extends PhpObject
$sRegEx = '(https?://|www\\.)(.*)'.$sCat.'(.*)\\.[a-zA-Z]{2,4}'; $sRegEx = '(https?://|www\\.)(.*)'.$sCat.'(.*)\\.[a-zA-Z]{2,4}';
break; break;
} }
$asResult = $this->oMySql->selectRows(array('select'=>array('id_message', 'nickname', 'message', 'led'), 'from'=>'messages', 'constraint'=>array('message'=>$sRegEx), 'constOpe'=>array('message'=>' REGEXP '))); $sMessageIdCol = MySqlManager::getId(self::MSG_TABLE);
$sChanIdCol = MySqlManager::getId(self::CHAN_TABLE);
$asResult = $this->oMySql->selectRows(array('select'=>array($sMessageIdCol, 'nickname', $sChanIdCol, 'message', 'led'),
'from'=>self::MSG_TABLE,
'constraint'=>array('message'=>$sRegEx),
'constOpe'=>array('message'=>' REGEXP ')));
$asChans = $this->oMySql->selectRows(array('select'=>array($sChanIdCol, 'safe_name'), 'from'=>self::CHAN_TABLE), true, $sChanIdCol);
$sPattern = '/(https?\:\/\/|www\.)[\S]+\.[a-zA-Z]{2,4}([\S]*)/ui'; $sPattern = '/(https?\:\/\/|www\.)[\S]+\.[a-zA-Z]{2,4}([\S]*)/ui';
foreach($asResult as $iLinkId=>$asRow) foreach($asResult as $iLinkId=>$asRow)
{ {
//get link out of message //filter on authorized chans
preg_match($sPattern, $asRow['message'], $asMatches); if($this->checkChanAuth($asChans[$asRow[$sChanIdCol]], $this->getUserId()))
$asRow['link'] = (substr($asMatches[0], 0, 4)=='http')?$asMatches[0]:'http://'.$asMatches[0]; {
//get link out of message
//add item preg_match($sPattern, $asRow['message'], $asMatches);
$sChatlink = $this->getInternalLink('chat', $asRow['id_message']); $asRow['link'] = (substr($asMatches[0], 0, 4)=='http')?$asMatches[0]:'http://'.$asMatches[0];
$asItem = array
( //add item
'title'=>'Lien'.($sCat==''?'':' - '.$sCat).' #'.($iLinkId+1), $sChatlink = $this->getInternalLink('chat', $asRow['id_message']);
'category'=>$sCat, $asItem = array
'description'=>'Lien post&eacute; par '.self::getNickNameFormat($asRow['nickname']).' &agrave; '.self::getDateFormat($asRow['led']).' : <a href="'.$asRow['link'].'" target="_blank">'.$asRow['message'].'</a>', (
'author'=>$asRow['nickname'], 'title'=>'Lien'.($sCat==''?'':' - '.$sCat).' #'.($iLinkId+1),
'link'=>$sChatlink, 'category'=>$sCat,
'pub_date'=>$asRow['led'], 'description'=>'Lien post&eacute; par '.self::getNickNameFormat($asRow['nickname']).' &agrave; '.self::getDateFormat($asRow['led']).' : <a href="'.$asRow['link'].'" target="_blank">'.$asRow['message'].'</a>',
'guid'=>$sChatlink 'author'=>$asRow['nickname'],
); 'link'=>$sChatlink,
$oFeed->addItem($asItem); 'pub_date'=>$asRow['led'],
'guid'=>$sChatlink
);
$oFeed->addItem($asItem);
}
} }
} }
@@ -944,32 +954,38 @@ class Databap extends PhpObject
//Add record in Search Table //Add record in Search Table
$this->oSearchEngine->buildIndex($iDbDocId, self::DOC_TYPE); $this->oSearchEngine->buildIndex($iDbDocId, self::DOC_TYPE);
return self::jsonExport(array('result'=>'success','doc_id'=>$iDbDocId)); //TODO add error handling
return $this->getJsonPostResult(self::SUCCESS, '', array('doc_id'=>$iDbDocId));
} }
public function getDoc($iDocId) public function getDoc($iDocId)
{ {
//Extract doc data //Extract doc data
$asDoc = $this->oMySql->selectRow(self::DOC_TABLE, $iDocId); $asDoc = $this->oMySql->selectRow(self::DOC_TABLE, $iDocId);
$asDoc['description'] = self::getDescriptionFormat($asDoc['description']); $bSuccess = !empty($asDoc);
$asDoc['title'] = self::getDescriptionFormat($asDoc['title']); $sDesc = '';
$asDoc['led'] = self::getDateFormat($asDoc['led']); if(!$bSuccess) $sDesc = self::NOT_FOUND;
else
//Extract extra data
$asUser = $this->getUserInfo($asDoc[MySqlManager::getId(self::USER_TABLE)]);
$asDoc['name'] = $asUser['name'];
$asDoc['company'] = $asUser['company'];
//Extract doc files
$sFileIdCol = MySqlManager::getId(self::FILE_TABLE);
$asFiles = $this->oMySql->selectRows(array('from'=>self::FILE_TABLE, 'constraint'=>array('id_item'=>$iDocId, 'type'=>self::DOC_TYPE)));
foreach($asFiles as $asFile)
{ {
$asDoc['files'][$asFile[$sFileIdCol]] = array( 'description' => self::getDescriptionFormat($asFile['description']), $asDoc['description'] = self::getDescriptionFormat($asDoc['description']);
'ext' => $asFile['extension']); $asDoc['title'] = self::getDescriptionFormat($asDoc['title']);
$asDoc['led'] = self::getDateFormat($asDoc['led']);
//Extract extra data
$asUser = $this->getUserInfo($asDoc[MySqlManager::getId(self::USER_TABLE)]);
$asDoc['name'] = $asUser['name'];
$asDoc['company'] = $asUser['company'];
//Extract doc files
$sFileIdCol = MySqlManager::getId(self::FILE_TABLE);
$asFiles = $this->oMySql->selectRows(array('from'=>self::FILE_TABLE, 'constraint'=>array('id_item'=>$iDocId, 'type'=>self::DOC_TYPE)));
foreach($asFiles as $asFile)
{
$asDoc['files'][$asFile[$sFileIdCol]] = array( 'description' => self::getDescriptionFormat($asFile['description']),
'ext' => $asFile['extension']);
}
} }
return $this->getJsonPostResult($bSuccess, $sDesc, $asDoc);
return self::jsonExport($asDoc);
} }
public function addTable($sSystem, $sTitle, $sDescription, $sKeyWords, $iPrevTableId, $bSimul=false) public function addTable($sSystem, $sTitle, $sDescription, $sKeyWords, $iPrevTableId, $bSimul=false)
@@ -1102,19 +1118,16 @@ class Databap extends PhpObject
return $sResult; return $sResult;
} }
public function uploadImage() public function uploadFile($sFileType)
{ {
switch($sFileType)
{
case 'image': $asAuthorizedTypes = self::$UPLOAD_IMG_EXTS; break;
case 'doc' : $asAuthorizedTypes = self::$UPLOAD_DOC_EXTS; break;
default : $asAuthorizedTypes = array();
}
$this->oClassManagement->incClass('fileuploader'); $this->oClassManagement->incClass('fileuploader');
$oFileUploader = new fileUploader(Procedure::IMAGE_FOLDER_TMP, self::$UPLOAD_IMG_EXTS); $oFileUploader = new fileUploader(self::DOC_TMP_FOLDER, $asAuthorizedTypes);
$asResult = $oFileUploader->handleUpload();
return $this->jsonConvert($asResult);
}
public function uploadDoc()
{
$this->oClassManagement->incClass('fileuploader');
$oFileUploader = new fileUploader(self::DOC_TMP_FOLDER, self::$UPLOAD_DOC_EXTS);
$asResult = $oFileUploader->handleUpload(); $asResult = $oFileUploader->handleUpload();
return $this->jsonConvert($asResult); return $this->jsonConvert($asResult);
@@ -1179,8 +1192,7 @@ class Databap extends PhpObject
private function getTableInfo($iTableId, $bFormatting=true) private function getTableInfo($iTableId, $bFormatting=true)
{ {
$asTable = $this->oMySql->selectRow(self::TABL_TABLE, $iTableId); $asTable = $this->oMySql->selectRow(self::TABL_TABLE, $iTableId);
if(!$asTable) $asTable = array(); //return false on empty if(!empty($asTable))
else
{ {
$asTable['timestamp'] = strtotime($asTable['led']); $asTable['timestamp'] = strtotime($asTable['led']);
if($bFormatting) if($bFormatting)
@@ -1852,10 +1864,8 @@ class Databap extends PhpObject
private function downloadToTmp($sUrl) private function downloadToTmp($sUrl)
{ {
$sFileInfo = pathinfo($sUrl); $sFilePath = self::DOC_TMP_FOLDER.uniqid();
$sImageExt = mb_strtolower($sFileInfo['extension']); return ToolBox::createThumbnail($sUrl, self::CHAT_IMG_MAX_WIDTH, self::CHAT_IMG_MAX_HEIGHT, $sFilePath, false, self::$UPLOAD_IMG_EXTS);
$sFilePath = self::DOC_TMP_FOLDER.uniqid().'.'.$sImageExt;
return ToolBox::createThumbnail($sUrl, self::CHAT_IMG_MAX_WIDTH, self::CHAT_IMG_MAX_HEIGHT, $sFilePath, false, Databap::$UPLOAD_IMG_EXTS);
} }
private function sendPM($iUserIdTo, $sMessage) private function sendPM($iUserIdTo, $sMessage)
@@ -2344,11 +2354,6 @@ class Databap extends PhpObject
return $oMask->getMask(); return $oMask->getMask();
} }
public static function checkNoAuthCookieResetAction($sAction)
{
return in_array($sAction, array('messages', 'upload_image', 'user_info', 'rss'));
}
public function logMeIn($sToken, $sAction) public function logMeIn($sToken, $sAction)
{ {
$iUserId = 0; $iUserId = 0;
@@ -2384,7 +2389,7 @@ class Databap extends PhpObject
$asUserInfo = $this->oMySql->selectRow(self::USER_TABLE, $asConstraints, array($sUserTableId, 'led')); $asUserInfo = $this->oMySql->selectRow(self::USER_TABLE, $asConstraints, array($sUserTableId, 'led'));
$iUserId = $asUserInfo[$sUserTableId]; $iUserId = $asUserInfo[$sUserTableId];
//Check pass reset necessity //Reset pass once a day
$bResetPass = (mb_substr($asUserInfo['led'], 0, 10) != date(Databap::DATE_SQL_FORMAT)); $bResetPass = (mb_substr($asUserInfo['led'], 0, 10) != date(Databap::DATE_SQL_FORMAT));
} }
} }
@@ -2398,10 +2403,7 @@ class Databap extends PhpObject
if($iUserId>0) if($iUserId>0)
{ {
$this->setUserId($iUserId); $this->setUserId($iUserId);
if(!self::checkNoAuthCookieResetAction($sAction) && $bResetPass) if($bResetPass) $this->resetAuthCookie();
{
$this->resetAuthCookie();
}
//Post-Redirect-Get if user manually logging from logon page //Post-Redirect-Get if user manually logging from logon page
if($sNameToken!='') if($sNameToken!='')

View File

@@ -516,21 +516,22 @@ class MySqlManager extends PhpObject
public function selectRow($sTableName, $asConstraints=array(), $sColumnName='*') public function selectRow($sTableName, $asConstraints=array(), $sColumnName='*')
{ {
if(!is_array($asConstraints)) //Table ID directly
{ if(!is_array($asConstraints)) $asConstraints = array($this->getId($sTableName)=>$asConstraints);
$asConstraints = array($this->getId($sTableName)=>$asConstraints);
} $asRows = $this->selectRows(array('select'=>$sColumnName, 'from'=>$sTableName, 'constraint'=>$asConstraints));
$asResult = $this->selectRows(array('select'=>$sColumnName, 'from'=>$sTableName, 'constraint'=>$asConstraints)); $iCountNb = count($asRows);
$iCountNb = count($asResult);
switch($iCountNb) switch($iCountNb)
{ {
case 0 : case 0 :
return false; $asResult = array();
break;
case $iCountNb > 1 : case $iCountNb > 1 :
$this->addError('Trop de r&eacute;sultats pour un selectRow() : '.$iCountNb.' lignes. Table: '.$sTableName.', contrainte: '.self::implodeAll($asConstraints, '=', ' ').', colonne: '.$sColumnName); $this->addError('Trop de r&eacute;sultats pour un selectRow() : '.$iCountNb.' lignes. Table: '.$sTableName.', contrainte: '.self::implodeAll($asConstraints, '=', ' ').', colonne: '.$sColumnName);
break; default:
$asResult = array_shift($asRows);
} }
return array_shift($asResult); return $asResult;
} }
public function selectValue($sTableName, $sColumnName, $oConstraints=array()) public function selectValue($sTableName, $sColumnName, $oConstraints=array())

View File

@@ -130,20 +130,48 @@ class ToolBox
return json_encode($asData); return json_encode($asData);
} }
public static function getMimeType($sPath, $bSubTypeOnly=false)
{
//Retrieving file Content Type
if(file_exists($sPath)) //Local
{
$oFileInfo = new finfo(FILEINFO_MIME);
$sMimetype = $oFileInfo->file($sPath);
}
else //Remote
{
$oCurl = curl_init($sPath);
curl_setopt($oCurl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($oCurl, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($oCurl, CURLOPT_HEADER, true);
curl_setopt($oCurl, CURLOPT_NOBODY, true);
curl_exec($oCurl);
$sMimetype = curl_getinfo($oCurl, CURLINFO_CONTENT_TYPE);
}
//Only sub type (after /)
if($bSubTypeOnly)
{
preg_match('`\/(?P<type>\w+)(\;|$)`ui', mb_strtolower($sMimetype), $asMatch);
$sMimetype = $asMatch['type'];
}
return $sMimetype;
}
public static function createThumbnail($sInPath, $iMaxWidth, $iMaxHeight, $sOutPath='', $bDeleteIn=false, $asImageExts=array('jpg', 'jpeg', 'gif', 'png'), $bCrop=false) public static function createThumbnail($sInPath, $iMaxWidth, $iMaxHeight, $sOutPath='', $bDeleteIn=false, $asImageExts=array('jpg', 'jpeg', 'gif', 'png'), $bCrop=false)
{ {
$asResult = array('error'=>''); $asResult = array('error'=>'');
//Look up the extension to choose the image creator //Look up the file type to choose the image creator
//TODO use MIME types $sImageExt = self::getMimeType($sInPath, true);
$sInInfo = pathinfo($sInPath);
$sInName = mb_strtolower($sInInfo['basename']);
$sImageExt = mb_strtolower($sInInfo['extension']);
$sImageExt = ($sImageExt=='jpg')?'jpeg':$sImageExt; $sImageExt = ($sImageExt=='jpg')?'jpeg':$sImageExt;
//New Destination folder //New Destination folder
$asInInfo = pathinfo($sInPath);
$asOutInfo = pathinfo($sOutPath);
if($sOutPath=='') $sOutPath = $sInPath; if($sOutPath=='') $sOutPath = $sInPath;
elseif(mb_substr($sOutPath, -1)=='/') $sOutPath .= $sInName; elseif(mb_substr($sOutPath, -1)=='/') $sOutPath .= mb_strtolower($asInInfo['basename']); //folder only, keep original name
elseif(!array_key_exists('extension', $asOutInfo)) $sOutPath .= '.'.$sImageExt; //folder + filename, but getting ext from file info
//New sizes //New sizes
if(in_array($sImageExt, $asImageExts)) if(in_array($sImageExt, $asImageExts))

View File

@@ -123,10 +123,10 @@ if($bUserOk && $sAction!=Databap::EXT_ACCESS)
$sResult = $oDatabap->redirectArticle($oItemId); $sResult = $oDatabap->redirectArticle($oItemId);
break; break;
case 'upload_image': case 'upload_image':
$sResult = $oDatabap->uploadImage(); $sResult = $oDatabap->uploadFile('image');
break; break;
case 'upload_file': case 'upload_doc':
$sResult = $oDatabap->uploadDoc(); $sResult = $oDatabap->uploadFile('doc');
break; break;
case 'url': case 'url':
$sResult = $oDatabap->checkValue(Databap::URL_TABLE, array('phrase'=>$sLink)); $sResult = $oDatabap->checkValue(Databap::URL_TABLE, array('phrase'=>$sLink));

14
jquery/databap.js vendored
View File

@@ -15,8 +15,8 @@ function Databap()
self.consts.app_image_folder = 'images/'; self.consts.app_image_folder = 'images/';
self.consts.add_code_text = 'Copier le code ici.'; self.consts.add_code_text = 'Copier le code ici.';
self.consts.search_box_text = 'Recherche...'; self.consts.search_box_text = 'Recherche...';
self.consts.maxHeight = $(window).height(); self.consts.maxHeight = $(window).innerHeight();
self.consts.maxWidth = $(window).width(); self.consts.maxWidth = $(window).innerWidth();
self.consts.time = (new Date()).getTime(); self.consts.time = (new Date()).getTime();
self.consts.transTime = 200; self.consts.transTime = 200;
@@ -408,15 +408,15 @@ function Databap()
{ {
//Maximize main div height to fill up the page //Maximize main div height to fill up the page
var iPageHeight = $('body').outerHeight(true); var iPageHeight = $('body').outerHeight(true);
var iWindowHeight = $(window).outerHeight(true); var iWindowHeight = $(window).innerHeight();
self.$main.height('+='+(iWindowHeight - iPageHeight)); self.$main.height('+='+(iWindowHeight - iPageHeight));
self.$menu.height($('#main_container').height()); self.$menu.height($('#main_container').height());
//Update size //Update size
self.consts.maxHeight = $(window).height(); self.consts.maxHeight = $(window).innerHeight();
self.consts.maxWidth = $(window).width(); self.consts.maxWidth = $(window).innerWidth();
self.consts.pageMaxHeight = self.$main.height(); self.consts.pageMaxHeight = self.$main.innerHeight();
self.consts.pageMaxWidth = self.$main.width(); self.consts.pageMaxWidth = self.$main.innerWidth();
//Page event //Page event
self.onResize(); self.onResize();

View File

@@ -859,16 +859,17 @@ function refresh_users()
databap.tmp(['users', databap.consts.all_chan_id, sSafeNickName], sNickName); databap.tmp(['users', databap.consts.all_chan_id, sSafeNickName], sNickName);
//Append name to user list box //Append name to user list box
var profileLink = databap.getInternalLink('profil', user_info.id_user); var sProfileLink = databap.getInternalLink('profil', user_info.id_user);
var mission = 'Mission actuelle : '+(user_info.status || 'Aucune'); var sMission = user_info.status || '';
var pm = 'Cliquez pour lancer un channel privé avec '+user_info.name+' ('+user_info.company+')'; var sLogoTitle = user_info.company+((sMission=='')?'':' (Mission : '+sMission+')');
var $user = $('<p>', {'class':'connected_user class_'+sChankeyName}) var sPm = user_info.name+((user_info.id_user==databap.vars.user_id)?'':' (cliquez pour lancer une conversation privée)');
.append($('<a>', {'class':'connected_user_logo', href:profileLink, title:mission, target:'_blank'}) var $User = $('<p>', {'class':'connected_user class_'+sChankeyName})
.append($('<a>', {'class':'connected_user_logo', href:sProfileLink, title:sLogoTitle, target:'_blank'})
.append($('<img>', {src:databap.consts.app_image_folder+user_info.logo})) .append($('<img>', {src:databap.consts.app_image_folder+user_info.logo}))
.append((user_info.afk=='1')?$('<i>', {class:'fa fa-c-afk afk'}):'')) .append((user_info.afk=='1')?$('<i>', {'class':'fa fa-c-afk afk'}):''))
.append($('<a>', {'class':'connected_user_name clickable '+sNickName.replace('"', '\''), id:user_info.id_user, title:pm}).text(sNickName)); .append($('<a>', {'class':'connected_user_name clickable '+sNickName.replace('"', '\''), id:user_info.id_user, title:sPm}).text(sNickName));
$user.find('.connected_user_name').click(joinPmChan); $User.find('.connected_user_name').click(joinPmChan);
databap.getMainElem('#connected_users').append($user); databap.getMainElem('#connected_users').append($User);
} }
); );
} }

View File

@@ -39,7 +39,7 @@ databap.pageInit = function()
( (
{ {
element: document.getElementById('attach_file'), element: document.getElementById('attach_file'),
action: databap.getActionLink('upload_file'), action: databap.getActionLink('upload_doc'),
allowedExtensions: databap.consts.authorized_file_exts, allowedExtensions: databap.consts.authorized_file_exts,
sizeLimit: parseInt(databap.consts.max_size)*100, sizeLimit: parseInt(databap.consts.max_size)*100,
addSlideText: 'Glisser les fichier ici', addSlideText: 'Glisser les fichier ici',
@@ -88,22 +88,31 @@ function loadDoc(iDocId, fOnSuccess)
'get_doc', 'get_doc',
function(doc_info) function(doc_info)
{ {
databap.getMainElem('#titles_read_title').html(doc_info.title); if(doc_info.desc == databap.consts.errors.not_found)
databap.getMainElem('#titles_read_user').html(doc_info.name);
databap.getMainElem('#titles_read_company').html(doc_info.company);
databap.getMainElem('#titles_read_led').html(doc_info.led);
databap.getMainElem('#titles_read_description').html(doc_info.description);
//links
for(var i in doc_info.files)
{ {
databap.getMainElem('#doc_links').addButton('file-'+doc_info.files[i].ext+' fa-30', databap.addErrorBefore('Documentation introuvable', '#submit_doc');
doc_info.files[i].description, databap.addSuccessBefore('Mais vous pouvez la créer !', '#submit_doc');
databap.getActionLink('dl_file', {id:i}), setDisplay('edit');
null, }
'inverse'); else
{
databap.getMainElem('#titles_read_title').html(doc_info.title);
databap.getMainElem('#titles_read_user').html(doc_info.name);
databap.getMainElem('#titles_read_company').html(doc_info.company);
databap.getMainElem('#titles_read_led').html(doc_info.led);
databap.getMainElem('#titles_read_description').html(doc_info.description);
//links
for(var i in doc_info.files)
{
databap.getMainElem('#doc_links').addButton('file-'+doc_info.files[i].ext+' fa-30',
doc_info.files[i].description,
databap.getActionLink('dl_file', {id:i}),
null,
'inverse');
}
setDisplay('read');
} }
setDisplay('read');
fOnSuccess(); fOnSuccess();
}, },
{id:iDocId}, {id:iDocId},
@@ -121,7 +130,7 @@ function saveDoc()
databap.getMainElem('#doc_form'), databap.getMainElem('#doc_form'),
function(data) function(data)
{ {
if(data.result == 'success') if(data.result == databap.consts.success)
{ {
databap.tmp('started', false); databap.tmp('started', false);
databap.goToInternalLink('doc', data.doc_id); databap.goToInternalLink('doc', data.doc_id);

View File

@@ -35,7 +35,8 @@ databap.pageInit = function()
//Add EHP improvements, SP bug fixes and WIP //Add EHP improvements, SP bug fixes and WIP
var $ActivityBox, sIcon; var $ActivityBox, sIcon;
var asActivityTypes = { var asActivityTypes = {
sp_fixes: [ 'Réparation des fichiers téléchargés (documentation)'], sp_fixes: [ 'Réparation des fichiers téléchargés (documentation)',
'Réparation du /img dans le chat : Le type de l\'image est lu dans le header de la requête http et non dans l\'extension'],
ehp_improvements: [ 'Utilisation des # pour les accès aux pages, compatible avec les boutons prec/suiv des navigateurs. Ex: <a href="#chat">databap.lutran.fr#chat</a>', ehp_improvements: [ 'Utilisation des # pour les accès aux pages, compatible avec les boutons prec/suiv des navigateurs. Ex: <a href="#chat">databap.lutran.fr#chat</a>',
'Mot de passe personnalisé et modifiable dans les <a href="#options">options</a>', 'Mot de passe personnalisé et modifiable dans les <a href="#options">options</a>',
'paramètre dans les <a href="#options">options</a> pour supprimer les messages d\'arrivée et de départ des gens (console)', 'paramètre dans les <a href="#options">options</a> pour supprimer les messages d\'arrivée et de départ des gens (console)',
@@ -48,6 +49,7 @@ databap.pageInit = function()
wip: [ 'Filtre par type de documents (table, code, procédure, ...) applicable post-recherche (affinage)', wip: [ 'Filtre par type de documents (table, code, procédure, ...) applicable post-recherche (affinage)',
'Messages non lus mémorisés par utilisateur. Possibilité d\'accéder à tous les messags non lus, mêmes plus anciens qu\'une journée<span class="round milestone"><i class="fa fa-c-version"></i>1.1</span>', 'Messages non lus mémorisés par utilisateur. Possibilité d\'accéder à tous les messags non lus, mêmes plus anciens qu\'une journée<span class="round milestone"><i class="fa fa-c-version"></i>1.1</span>',
'Son lors de nouveaux messages (chat)', 'Son lors de nouveaux messages (chat)',
'lecteur de fichier online (pdf, txt, image, word ?)',
'Version compatible mobile (surtout pour le chat)', 'Version compatible mobile (surtout pour le chat)',
'Accès externe à certains fichiers (partage temporaire)', 'Accès externe à certains fichiers (partage temporaire)',
'Messagerie interne afin d\'envoyer des mails aux personnes absentes<span class="round milestone"><i class="fa fa-c-version"></i>1.2</span>', 'Messagerie interne afin d\'envoyer des mails aux personnes absentes<span class="round milestone"><i class="fa fa-c-version"></i>1.2</span>',

3
todo
View File

@@ -7,15 +7,16 @@ Internal:
- Independant Option Class - Independant Option Class
- put feedback box in title - put feedback box in title
- Créer un fichier de testing - Créer un fichier de testing
- harmonize local file access: table "files" ? No file name / extension on server
Bug fix: Bug fix:
- [1.0.3] Check le document type plutot que l'extension pour les /img
- [1.0.3] Resize .gif - [1.0.3] Resize .gif
- Fix les "xxx se déconnecte" intempestives - Fix les "xxx se déconnecte" intempestives
- code reader : mettre la scrollbar à l'intérieur du code - code reader : mettre la scrollbar à l'intérieur du code
- Trouver une meilleure place pour le menu - Trouver une meilleure place pour le menu
New features: New features:
- [1.1.0] Chat: New "Connected Users" Panel: On click, opening a sub panl with icons: profil link, status, PM.
- [1.1.0] Unread messages par user (dedicated table). No more daily cut - [1.1.0] Unread messages par user (dedicated table). No more daily cut
- [1.1.0] Refiltre par type dans le search - [1.1.0] Refiltre par type dans le search
- [1.1.0] Remplacer dans les options : oui / non par [-0] (f205) [O-] (f204) - [1.1.0] Remplacer dans les options : oui / non par [-0] (f205) [O-] (f204)