diff --git a/inc/databap.php b/inc/databap.php index 9e601f3..acf69ca 100755 --- a/inc/databap.php +++ b/inc/databap.php @@ -512,28 +512,38 @@ class Databap extends PhpObject $sRegEx = '(https?://|www\\.)(.*)'.$sCat.'(.*)\\.[a-zA-Z]{2,4}'; 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'; foreach($asResult as $iLinkId=>$asRow) { - //get link out of message - preg_match($sPattern, $asRow['message'], $asMatches); - $asRow['link'] = (substr($asMatches[0], 0, 4)=='http')?$asMatches[0]:'http://'.$asMatches[0]; - - //add item - $sChatlink = $this->getInternalLink('chat', $asRow['id_message']); - $asItem = array - ( - 'title'=>'Lien'.($sCat==''?'':' - '.$sCat).' #'.($iLinkId+1), - 'category'=>$sCat, - 'description'=>'Lien posté par '.self::getNickNameFormat($asRow['nickname']).' à '.self::getDateFormat($asRow['led']).' : '.$asRow['message'].'', - 'author'=>$asRow['nickname'], - 'link'=>$sChatlink, - 'pub_date'=>$asRow['led'], - 'guid'=>$sChatlink - ); - $oFeed->addItem($asItem); + //filter on authorized chans + if($this->checkChanAuth($asChans[$asRow[$sChanIdCol]], $this->getUserId())) + { + //get link out of message + preg_match($sPattern, $asRow['message'], $asMatches); + $asRow['link'] = (substr($asMatches[0], 0, 4)=='http')?$asMatches[0]:'http://'.$asMatches[0]; + + //add item + $sChatlink = $this->getInternalLink('chat', $asRow['id_message']); + $asItem = array + ( + 'title'=>'Lien'.($sCat==''?'':' - '.$sCat).' #'.($iLinkId+1), + 'category'=>$sCat, + 'description'=>'Lien posté par '.self::getNickNameFormat($asRow['nickname']).' à '.self::getDateFormat($asRow['led']).' : '.$asRow['message'].'', + 'author'=>$asRow['nickname'], + 'link'=>$sChatlink, + 'pub_date'=>$asRow['led'], + 'guid'=>$sChatlink + ); + $oFeed->addItem($asItem); + } } } @@ -944,32 +954,38 @@ class Databap extends PhpObject //Add record in Search Table $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) { //Extract doc data $asDoc = $this->oMySql->selectRow(self::DOC_TABLE, $iDocId); - $asDoc['description'] = self::getDescriptionFormat($asDoc['description']); - $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) + $bSuccess = !empty($asDoc); + $sDesc = ''; + if(!$bSuccess) $sDesc = self::NOT_FOUND; + else { - $asDoc['files'][$asFile[$sFileIdCol]] = array( 'description' => self::getDescriptionFormat($asFile['description']), - 'ext' => $asFile['extension']); + $asDoc['description'] = self::getDescriptionFormat($asDoc['description']); + $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 self::jsonExport($asDoc); + return $this->getJsonPostResult($bSuccess, $sDesc, $asDoc); } public function addTable($sSystem, $sTitle, $sDescription, $sKeyWords, $iPrevTableId, $bSimul=false) @@ -1102,19 +1118,16 @@ class Databap extends PhpObject 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'); - $oFileUploader = new fileUploader(Procedure::IMAGE_FOLDER_TMP, self::$UPLOAD_IMG_EXTS); - $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); + $oFileUploader = new fileUploader(self::DOC_TMP_FOLDER, $asAuthorizedTypes); $asResult = $oFileUploader->handleUpload(); return $this->jsonConvert($asResult); @@ -1179,8 +1192,7 @@ class Databap extends PhpObject private function getTableInfo($iTableId, $bFormatting=true) { $asTable = $this->oMySql->selectRow(self::TABL_TABLE, $iTableId); - if(!$asTable) $asTable = array(); //return false on empty - else + if(!empty($asTable)) { $asTable['timestamp'] = strtotime($asTable['led']); if($bFormatting) @@ -1852,10 +1864,8 @@ class Databap extends PhpObject private function downloadToTmp($sUrl) { - $sFileInfo = pathinfo($sUrl); - $sImageExt = mb_strtolower($sFileInfo['extension']); - $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); + $sFilePath = self::DOC_TMP_FOLDER.uniqid(); + return ToolBox::createThumbnail($sUrl, self::CHAT_IMG_MAX_WIDTH, self::CHAT_IMG_MAX_HEIGHT, $sFilePath, false, self::$UPLOAD_IMG_EXTS); } private function sendPM($iUserIdTo, $sMessage) @@ -2344,11 +2354,6 @@ class Databap extends PhpObject return $oMask->getMask(); } - public static function checkNoAuthCookieResetAction($sAction) - { - return in_array($sAction, array('messages', 'upload_image', 'user_info', 'rss')); - } - public function logMeIn($sToken, $sAction) { $iUserId = 0; @@ -2384,7 +2389,7 @@ class Databap extends PhpObject $asUserInfo = $this->oMySql->selectRow(self::USER_TABLE, $asConstraints, array($sUserTableId, 'led')); $iUserId = $asUserInfo[$sUserTableId]; - //Check pass reset necessity + //Reset pass once a day $bResetPass = (mb_substr($asUserInfo['led'], 0, 10) != date(Databap::DATE_SQL_FORMAT)); } } @@ -2398,10 +2403,7 @@ class Databap extends PhpObject if($iUserId>0) { $this->setUserId($iUserId); - if(!self::checkNoAuthCookieResetAction($sAction) && $bResetPass) - { - $this->resetAuthCookie(); - } + if($bResetPass) $this->resetAuthCookie(); //Post-Redirect-Get if user manually logging from logon page if($sNameToken!='') diff --git a/inc/mysqlmanager.php b/inc/mysqlmanager.php index 342d675..c792638 100644 --- a/inc/mysqlmanager.php +++ b/inc/mysqlmanager.php @@ -516,21 +516,22 @@ class MySqlManager extends PhpObject public function selectRow($sTableName, $asConstraints=array(), $sColumnName='*') { - if(!is_array($asConstraints)) - { - $asConstraints = array($this->getId($sTableName)=>$asConstraints); - } - $asResult = $this->selectRows(array('select'=>$sColumnName, 'from'=>$sTableName, 'constraint'=>$asConstraints)); - $iCountNb = count($asResult); + //Table ID directly + if(!is_array($asConstraints)) $asConstraints = array($this->getId($sTableName)=>$asConstraints); + + $asRows = $this->selectRows(array('select'=>$sColumnName, 'from'=>$sTableName, 'constraint'=>$asConstraints)); + $iCountNb = count($asRows); switch($iCountNb) { case 0 : - return false; + $asResult = array(); + break; case $iCountNb > 1 : $this->addError('Trop de ré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()) diff --git a/inc/toolbox.php b/inc/toolbox.php index c138a29..40211fb 100644 --- a/inc/toolbox.php +++ b/inc/toolbox.php @@ -130,20 +130,48 @@ class ToolBox 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\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) { $asResult = array('error'=>''); - //Look up the extension to choose the image creator - //TODO use MIME types - $sInInfo = pathinfo($sInPath); - $sInName = mb_strtolower($sInInfo['basename']); - $sImageExt = mb_strtolower($sInInfo['extension']); + //Look up the file type to choose the image creator + $sImageExt = self::getMimeType($sInPath, true); $sImageExt = ($sImageExt=='jpg')?'jpeg':$sImageExt; //New Destination folder + $asInInfo = pathinfo($sInPath); + $asOutInfo = pathinfo($sOutPath); 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 if(in_array($sImageExt, $asImageExts)) diff --git a/index.php b/index.php index cc0cb54..29deb3a 100644 --- a/index.php +++ b/index.php @@ -123,10 +123,10 @@ if($bUserOk && $sAction!=Databap::EXT_ACCESS) $sResult = $oDatabap->redirectArticle($oItemId); break; case 'upload_image': - $sResult = $oDatabap->uploadImage(); + $sResult = $oDatabap->uploadFile('image'); break; - case 'upload_file': - $sResult = $oDatabap->uploadDoc(); + case 'upload_doc': + $sResult = $oDatabap->uploadFile('doc'); break; case 'url': $sResult = $oDatabap->checkValue(Databap::URL_TABLE, array('phrase'=>$sLink)); diff --git a/jquery/databap.js b/jquery/databap.js index 47c3aea..399d2f6 100644 --- a/jquery/databap.js +++ b/jquery/databap.js @@ -15,8 +15,8 @@ function Databap() self.consts.app_image_folder = 'images/'; self.consts.add_code_text = 'Copier le code ici.'; self.consts.search_box_text = 'Recherche...'; - self.consts.maxHeight = $(window).height(); - self.consts.maxWidth = $(window).width(); + self.consts.maxHeight = $(window).innerHeight(); + self.consts.maxWidth = $(window).innerWidth(); self.consts.time = (new Date()).getTime(); self.consts.transTime = 200; @@ -408,15 +408,15 @@ function Databap() { //Maximize main div height to fill up the page var iPageHeight = $('body').outerHeight(true); - var iWindowHeight = $(window).outerHeight(true); + var iWindowHeight = $(window).innerHeight(); self.$main.height('+='+(iWindowHeight - iPageHeight)); self.$menu.height($('#main_container').height()); //Update size - self.consts.maxHeight = $(window).height(); - self.consts.maxWidth = $(window).width(); - self.consts.pageMaxHeight = self.$main.height(); - self.consts.pageMaxWidth = self.$main.width(); + self.consts.maxHeight = $(window).innerHeight(); + self.consts.maxWidth = $(window).innerWidth(); + self.consts.pageMaxHeight = self.$main.innerHeight(); + self.consts.pageMaxWidth = self.$main.innerWidth(); //Page event self.onResize(); diff --git a/masks/chat.html b/masks/chat.html index 7d5fc15..2e7dff9 100755 --- a/masks/chat.html +++ b/masks/chat.html @@ -859,16 +859,17 @@ function refresh_users() databap.tmp(['users', databap.consts.all_chan_id, sSafeNickName], sNickName); //Append name to user list box - var profileLink = databap.getInternalLink('profil', user_info.id_user); - var mission = 'Mission actuelle : '+(user_info.status || 'Aucune'); - var pm = 'Cliquez pour lancer un channel privé avec '+user_info.name+' ('+user_info.company+')'; - var $user = $('

', {'class':'connected_user class_'+sChankeyName}) - .append($('', {'class':'connected_user_logo', href:profileLink, title:mission, target:'_blank'}) + var sProfileLink = databap.getInternalLink('profil', user_info.id_user); + var sMission = user_info.status || ''; + var sLogoTitle = user_info.company+((sMission=='')?'':' (Mission : '+sMission+')'); + var sPm = user_info.name+((user_info.id_user==databap.vars.user_id)?'':' (cliquez pour lancer une conversation privée)'); + var $User = $('

', {'class':'connected_user class_'+sChankeyName}) + .append($('', {'class':'connected_user_logo', href:sProfileLink, title:sLogoTitle, target:'_blank'}) .append($('', {src:databap.consts.app_image_folder+user_info.logo})) - .append((user_info.afk=='1')?$('', {class:'fa fa-c-afk afk'}):'')) - .append($('', {'class':'connected_user_name clickable '+sNickName.replace('"', '\''), id:user_info.id_user, title:pm}).text(sNickName)); - $user.find('.connected_user_name').click(joinPmChan); - databap.getMainElem('#connected_users').append($user); + .append((user_info.afk=='1')?$('', {'class':'fa fa-c-afk afk'}):'')) + .append($('', {'class':'connected_user_name clickable '+sNickName.replace('"', '\''), id:user_info.id_user, title:sPm}).text(sNickName)); + $User.find('.connected_user_name').click(joinPmChan); + databap.getMainElem('#connected_users').append($User); } ); } diff --git a/masks/doc.html b/masks/doc.html index 11b6828..1287d6c 100755 --- a/masks/doc.html +++ b/masks/doc.html @@ -39,7 +39,7 @@ databap.pageInit = function() ( { element: document.getElementById('attach_file'), - action: databap.getActionLink('upload_file'), + action: databap.getActionLink('upload_doc'), allowedExtensions: databap.consts.authorized_file_exts, sizeLimit: parseInt(databap.consts.max_size)*100, addSlideText: 'Glisser les fichier ici', @@ -88,22 +88,31 @@ function loadDoc(iDocId, fOnSuccess) 'get_doc', function(doc_info) { - 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) + if(doc_info.desc == databap.consts.errors.not_found) { - 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'); + databap.addErrorBefore('Documentation introuvable', '#submit_doc'); + databap.addSuccessBefore('Mais vous pouvez la créer !', '#submit_doc'); + setDisplay('edit'); + } + 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(); }, {id:iDocId}, @@ -121,7 +130,7 @@ function saveDoc() databap.getMainElem('#doc_form'), function(data) { - if(data.result == 'success') + if(data.result == databap.consts.success) { databap.tmp('started', false); databap.goToInternalLink('doc', data.doc_id); diff --git a/masks/welcome.html b/masks/welcome.html index f31643a..d11f8d7 100755 --- a/masks/welcome.html +++ b/masks/welcome.html @@ -35,7 +35,8 @@ databap.pageInit = function() //Add EHP improvements, SP bug fixes and WIP var $ActivityBox, sIcon; 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: databap.lutran.fr#chat', 'Mot de passe personnalisé et modifiable dans les options', 'paramètre dans les options 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)', 'Messages non lus mémorisés par utilisateur. Possibilité d\'accéder à tous les messags non lus, mêmes plus anciens qu\'une journée1.1', 'Son lors de nouveaux messages (chat)', + 'lecteur de fichier online (pdf, txt, image, word ?)', 'Version compatible mobile (surtout pour le chat)', 'Accès externe à certains fichiers (partage temporaire)', 'Messagerie interne afin d\'envoyer des mails aux personnes absentes1.2', diff --git a/todo b/todo index adb5aa6..21e3a52 100644 --- a/todo +++ b/todo @@ -7,15 +7,16 @@ Internal: - Independant Option Class - put feedback box in title - Créer un fichier de testing +- harmonize local file access: table "files" ? No file name / extension on server Bug fix: -- [1.0.3] Check le document type plutot que l'extension pour les /img - [1.0.3] Resize .gif - Fix les "xxx se déconnecte" intempestives - code reader : mettre la scrollbar à l'intérieur du code - Trouver une meilleure place pour le menu 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] Refiltre par type dans le search - [1.1.0] Remplacer dans les options : oui / non par [-0] (f205) [O-] (f204)