1
0
Fork 0
mirror of https://github.com/YunoHost-Apps/minchat_ynh.git synced 2024-09-03 19:36:29 +02:00
This commit is contained in:
Chtixof 2015-04-06 17:46:57 +02:00
parent 8bd60d3aba
commit 2d3d716f61
15 changed files with 638 additions and 0 deletions

21
LICENSE.txt Normal file
View file

@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2015 Chtixof
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

18
README.md Normal file
View file

@ -0,0 +1,18 @@
# minchat_ynh : minchat for Yunohost
minchat_ynh is a free minimalist chat application packaged for [Yunohost](https://yunohost.org).
It is based on [wojtek77/chat](https://github.com/wojtek77/chat), itself based on [Gabriel Nava's tutorial](http://code.tutsplus.com/tutorials/how-to-create-a-simple-web-based-chat-application--net-5931).
## Features
- No need for users to register. Just need the web address.
- On connection, the page is feeded with the 50 last messages.
- Optional *get* arguments to specify the user name and the room. Example : ...minchat/?name=John&room=Living
- Mono room (for now)
## Installation
### On Yunohost
Via the admin web console, type in: <https://github.com/chtixof/minchat_ynh>
Or on ssh : `sudo yunohost app install https://github.com/chtixof/minchat_ynh`
### Otherwise
Download, unzip and just copy the content of the `source` folder to any folder of your web site.

18
conf/nginx.conf Normal file
View file

@ -0,0 +1,18 @@
location PATHTOCHANGE {
alias WWWPATH ;
index index.html index.php ;
try_files $uri $uri/ index.php;
location ~ [^/]\.php(/|$) {
fastcgi_split_path_info ^(.+?\.php)(/.*)$;
fastcgi_pass unix:/var/run/php5-fpm.sock;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param REMOTE_USER $remote_user;
fastcgi_param PATH_INFO $fastcgi_path_info;
}
# Include SSOWAT user panel.
include conf.d/yunohost_panel.conf.inc;
}

39
manifest.json Normal file
View file

@ -0,0 +1,39 @@
{
"name": "minchat",
"id": "minchat",
"description": {
"en": "A minimalist web chat",
"fr": "Un web chat minimaliste"
},
"license": "MIT",
"developer": {
"name": "chtixof"
},
"multi_instance": "false",
"arguments": {
"install" : [ {
"name": "domain",
"ask": {
"en": "Choose a domain for minchat",
"en": "Choisissez un domaine pour minchat"
},
"example": "domain.org"
},{
"name": "path",
"ask": {
"en": "Choose a path for minchat",
"en": "Choisissez un chemin pour minchat"
},
"example": "/minchat",
"default": "/minchat"
},{
"name": "ispublic",
"ask": {
"en": "Is it a public site (Y)",
"en": "Taper Y si le site est public"
},
"example": "Y",
"default": "Y"
} ]
}
}

15
scripts/backup Normal file
View file

@ -0,0 +1,15 @@
#!/bin/bash
app=minchat
# The parameter $1 is the backup directory location
# which will be compressed afterward
backup_dir=$1/apps/$app
mkdir -p $backup_dir
# Backup sources & data
sudo cp -a /var/www/$app/. $backup_dir/sources
# Copy Nginx and YunoHost parameters to make the script "standalone"
sudo cp -a /etc/yunohost/apps/$app/. $backup_dir/yunohost
domain=$(sudo yunohost app setting $app domain)
sudo cp -a /etc/nginx/conf.d/$domain.d/$app.conf $backup_dir/nginx.conf

35
scripts/install Normal file
View file

@ -0,0 +1,35 @@
#!/bin/bash
# Installation de minchat dans Yunohost
app=minchat
# Retrieve arguments
domain=$1
path=$2
is_public=$3
# Check domain/path availability
sudo yunohost app checkurl $domain$path -a $app
if [[ ! $? -eq 0 ]]; then
exit 1
fi
# Copy files to the right place with the right permissions
final_path=/var/www/$app
sudo mkdir -p $final_path
sudo cp -a ../sources/* $final_path
sudo chown -R www-data: $final_path
# Modify Nginx configuration file and copy it to Nginx conf directory
sed -i "s@PATHTOCHANGE@$path@g" ../conf/nginx.conf
sed -i "s@WWWPATH@$final_path@g" ../conf/nginx.conf
sudo cp ../conf/nginx.conf /etc/nginx/conf.d/$domain.d/$app.conf
# Make it public is required
if [[ $is_public =~ ^[Yy]$ ]]
then
sudo yunohost app setting $app skipped_uris -v "/"
fi
# Reload nginx and regenerate SSOwat conf
sudo service nginx reload
sudo yunohost app ssowatconf

15
scripts/remove Normal file
View file

@ -0,0 +1,15 @@
#!/bin/bash
app=minchat
# Retrieve arguments
domain=$(sudo yunohost app setting $app domain)
# Remove sources
sudo rm -rf /var/www/$app
# Remove configuration files
sudo rm -f /etc/nginx/conf.d/$domain.d/$app.conf
# Restart services
sudo service nginx reload
sudo yunohost app ssowatconf

16
scripts/restore Normal file
View file

@ -0,0 +1,16 @@
#!/bin/bash
app=minchat
# The parameter $1 is the uncompressed restore directory location
backup_dir=$1/apps/$app
# Restore sources & data
sudo cp -a $backup_dir/sources/. /var/www/$app
# Restore Nginx and YunoHost parameters
sudo cp -a $backup_dir/yunohost/. /etc/yunohost/apps/$app
domain=$(sudo yunohost app setting $app domain)
sudo cp -a $backup_dir/nginx.conf /etc/nginx/conf.d/$domain.d/$app.conf
# Restart webserver
sudo service nginx reload

24
scripts/upgrade Normal file
View file

@ -0,0 +1,24 @@
#!/bin/bash
app=minchat
# Retrieve arguments
domain=$(sudo yunohost app setting $app domain)
path=$(sudo yunohost app setting $app path)
# Remove trailing "/" for next commands
path=${path%/}
# Copy source files
final_path=/var/www/$app
sudo mkdir -p $final_path
sudo cp -a ../sources/* $final_path
# Modify Nginx configuration file and copy it to Nginx conf directory
sed -i "s@PATHTOCHANGE@$path@g" ../conf/nginx.conf
sed -i "s@WWWPATH@$final_path@g" ../conf/nginx.conf
sudo cp ../conf/nginx.conf /etc/nginx/conf.d/$domain.d/$app.conf
# Restart services
sudo service nginx reload
sudo yunohost app ssowatconf

173
sources/index.php Normal file
View file

@ -0,0 +1,173 @@
<?php
function v($v, $czyscHtmlIExit = false) {
if ($czyscHtmlIExit) ob_end_clean();
echo '<pre>' . print_r($v, true) . '</pre>';
if ($czyscHtmlIExit) exit;
}
function vv($v, $czyscHtmlIExit = false) {
if ($czyscHtmlIExit) ob_end_clean();
echo '<pre>';
var_dump($v);
echo '</pre>';
if ($czyscHtmlIExit) exit;
}
function vvv($var, & $result = null, $is_view = true)
{
if (is_array($var) || is_object($var)) foreach ($var as $key=> $value) vvv($value, $result[$key], false);
else $result = $var;
if ($is_view) v($result);
}
function loginForm() {
echo'
<div id="loginform">
<form action="" method="post">
<p>Please enter your name to continue:</p>
<label for="name">Name:</label>
<input type="text" name="name" id="name"/>
<input type="submit" name="enter" id="enter" value="Enter" />
</form>
</div>
';
}
function getSetup($key = null) {
$arr = parse_ini_file('setup.ini');
return isset($key) ? $arr[$key] : $arr;
}
function deleteOldHistory() {
$expireHistory = getSetup('expire_history');
$expireDate = date('Y-m-d', strtotime("-$expireHistory day"));
foreach (glob('./history/*') as $f) {
if (basename($f) < $expireDate) {
unlink($f);
}
}
}
//-------------------------
session_start();
if (isset($_GET['logout'])) {
session_destroy();
header("Location: ./"); //Redirect the user
}
if (isset($_REQUEST['name'])) {
if ($_REQUEST['name'] != "") {
$_SESSION['name'] = stripslashes(htmlspecialchars($_REQUEST['name']));
} else {
echo '<span class="error">Please type in a name</span>';
}
}
if (isset($_REQUEST['room'])) {
$room = $_REQUEST['room'];
} else {
$room = "";
}
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Chat - Customer Module</title>
<link type="text/css" rel="stylesheet" href="style.css" />
</head>
<?php
if (!isset($_SESSION['name'])) {
loginForm();
deleteOldHistory();
} else {
?>
<div id="wrapper">
<div id="menu">
<p class="welcome">Welcome to the <b><?php echo $room; ?></b> room, <b><?php echo $_SESSION['name']; ?></b></p>
<div style="clear:both"></div>
</div>
<div id="chatbox"><?php
?></div>
<form name="message" action="">
<input name="usermsg" type="text" id="usermsg" size="63" autocomplete="off" autofocus/>
<input name="submitmsg" type="submit" id="submitmsg" value="Send" />
</form>
</div>
<script type="text/javascript" src="lib/jquery-2.1.3.min.js"></script>
<script type="text/javascript">
// jQuery Document
$(document).ready(function() {
var id = 'undefined';
//If user submits the form
$("#submitmsg").click(function() {
var clientmsg = $("#usermsg").val();
$("#usermsg").val('');
$("#usermsg").focus();
$.ajax({
type: 'POST',
url: 'post.php',
data: {text: clientmsg},
//cache: false,
async: false,
success: function(data) {
loadLog();
},
error: function(request, status, error) {
$("#usermsg").val(clientmsg);
},
});
return false;
});
//Load the file containing the chat log
function loadLog() {
var oldscrollHeight = $("#chatbox")[0].scrollHeight;
$.ajax({
type: 'POST',
url: 'server.php',
data: {id: id},
dataType: 'json',
//cache: false,
async: false,
success: function(data) {
id = data.id;
var html = '';
var date;
for (var k in data.data.reverse()) {
date = new Date(parseInt(data.data[k][0])*1000);
date = date.toLocaleTimeString();
date = date.replace(/([\d]+\D+[\d]{2})\D+[\d]{2}(.*)/, '$1$2');
html = html
+"<div class='msgln'>("+date+") <b>"
+data.data[k][1]+"</b>: "+data.data[k][2]+"<br></div>";
}
$("#chatbox").append(html); //Insert chat messages into the #chatbox div
var newscrollHeight = $("#chatbox")[0].scrollHeight;
if (newscrollHeight > oldscrollHeight) {
$("#chatbox").scrollTop($("#chatbox")[0].scrollHeight);
}
},
});
}
loadLog();
setInterval(loadLog, <?php echo getSetup('interval') ?>); //Reload file every 2.5 seconds
//If user wants to end session
$("#exit").click(function() {
var exit = confirm("Are you sure you want to end the session?");
if (exit == true) {
window.location = 'index.php?logout=true';
}
});
});
</script>
<?php
}
?>
</body>
</html>

4
sources/lib/jquery-2.1.3.min.js vendored Normal file

File diff suppressed because one or more lines are too long

103
sources/post.php Normal file
View file

@ -0,0 +1,103 @@
<?php
function v($v, $czyscHtmlIExit = false) {
if ($czyscHtmlIExit) ob_end_clean();
echo '<pre>' . print_r($v, true) . '</pre>';
if ($czyscHtmlIExit) exit;
}
function vv($v, $czyscHtmlIExit = false) {
if ($czyscHtmlIExit) ob_end_clean();
echo '<pre>';
var_dump($v);
echo '</pre>';
if ($czyscHtmlIExit) exit;
}
function vvv($var, & $result = null, $is_view = true)
{
if (is_array($var) || is_object($var)) foreach ($var as $key=> $value) vvv($value, $result[$key], false);
else $result = $var;
if ($is_view) v($result);
}
function getSetup($key = null) {
$arr = parse_ini_file('setup.ini');
return isset($key) ? $arr[$key] : $arr;
}
//$_POST['text'] = 'abc';
session_start();
if (!isset($_SESSION['name'])) return;
$text = isset($_POST['text']) ? $_POST['text'] : '';
if ($text === '') return;
$isApc = extension_loaded('apc');
$setup = getSetup();
$time = time();
$date = date('Y-m-d', $time);
$uniqid = uniqid();
$id = $time.'-'.$uniqid;
$tmpDir = './tmp/';
$historyDir = './history/';
$tmpFile = $tmpDir.'cache';
$historyFile = $historyDir.$date;
$fh = @fopen($historyFile, 'a');
if ($fh === false) {
mkdir($historyDir);
if (!is_dir($tmpDir)) mkdir($tmpDir);
$fh = @fopen($historyFile, 'a');
}
/* start semafore */
flock($fh, LOCK_EX);
// data
$data = array($id, $_SESSION['name'], stripslashes(htmlspecialchars($text)));
// write history
fwrite($fh, implode('&', $data)."\n");
// cache
if ($isApc) {
$cache = apc_fetch('chat');
if ($cache === false) {
$cache = array();
}
} else {
$cache = @file_get_contents($tmpFile);
if ($cache === false) {
$cache = array();
} else {
$cache = unserialize($cache);
}
}
array_unshift($cache, $data);
// delete expired cache
$expireTime = floor($time - $setup['interval']/1000 - $setup['expire_cache']);
foreach (array_reverse($cache,true) as $k => $e) {
if ($e[0] < $expireTime) {
unset($cache[$k]);
} else {
break;
}
}
if ($isApc) {
apc_store('chat', $cache);
} else {
file_put_contents($tmpFile, serialize($cache));
}
/* end semafore */
flock($fh, LOCK_UN);
fclose($fh);

77
sources/server.php Normal file
View file

@ -0,0 +1,77 @@
<?php
function v($v, $czyscHtmlIExit = false) {
if ($czyscHtmlIExit) ob_end_clean();
echo '<pre>' . print_r($v, true) . '</pre>';
if ($czyscHtmlIExit) exit;
}
function vv($v, $czyscHtmlIExit = false) {
if ($czyscHtmlIExit) ob_end_clean();
echo '<pre>';
var_dump($v);
echo '</pre>';
if ($czyscHtmlIExit) exit;
}
function vvv($var, & $result = null, $is_view = true)
{
if (is_array($var) || is_object($var)) foreach ($var as $key=> $value) vvv($value, $result[$key], false);
else $result = $var;
if ($is_view) v($result);
}
//$_POST['id'] = '1305177620-53c14f147c456';
if (!isset($_POST['id'])) return;
$isApc = extension_loaded('apc');
$id = $_POST['id'];
$cache = $isApc ? apc_fetch('chat') : @unserialize(file_get_contents('./tmp/cache'));
$data = array();
if ($id === 'undefined') {
$id = empty($cache) ? 0 : $cache[0][0];
// first refresh : loads 50 last msg from history
$file = './history/'.date('Y-m-d');
if (file_exists($file)) {
$history = file($file, FILE_IGNORE_NEW_LINES);
$history = array_reverse($history);
foreach ($history as & $ref) {
$ref = explode('&', $ref);
}
$data = array_slice($history, 0, 50);
}
} elseif ($id === '0') {
if (!empty($cache)) {
$id = $cache[0][0];
$data = $cache;
}
} else {
$end = end($cache);
// read data from cache
if ($id >= $end[0]) {
foreach ($cache as $k => $c) {
if ($c[0] === $id) break;
}
$data = array_slice($cache, 0, $k);
}
// read data from history (any problem witch Internet and are delays)
else {
$date = date('Y-m-d');
$history = array();
while (($history = array_merge(file('./history/'.$date, FILE_IGNORE_NEW_LINES), $history)) && $history[0] > $id) {
$date = date('Y-m-d', strtotime('-1 day', strtotime($date)));
if (!file_exists('./history/'.$date)) break;
}
// prepare history
$history = array_reverse($history);
foreach ($history as & $ref) {
$ref = explode('&', $ref);
}
// get data
foreach ($history as $k => $h) {
if ($h[0] === $id) break;
}
$data = array_slice($history, 0, $k);
}
$id = $cache[0][0];
}
echo json_encode(array('id' => $id, 'data' => $data));

9
sources/setup.ini Normal file
View file

@ -0,0 +1,9 @@
; how often get data from serwer
interval = 2500 ; in milliseconds
; extra time for cache when is problem with Internet
expire_cache = 60 ; in seconds
; time for history
expire_history = 1 ; in days

71
sources/style.css Normal file
View file

@ -0,0 +1,71 @@
/* CSS Document */
html {
height: 100%;
margin: 0;
padding: 0; }
body {
height: 100%;
font: 100% arial;
margin: 0;
padding: 0; }
p, span {
margin: 0;
padding: 0; }
form {
margin: 10px 50px;
padding: 0;
}
input {
background: #FEFFF4;
font: 110% arial; }
input[type=submit] {
font-size: 100%;
}
a {
color: #0000FF;
text-decoration: none; }
a:hover { text-decoration: underline; }
#wrapper, #loginform {
background: #d8d8d8;
width: 100%;
height: 100%;
}
#loginform { padding-top: 18px; width: 50%; height: auto; padding-top: 1.5em; padding-bottom: 2.5em; }
#loginform p { margin: 5px; }
#chatbox {
text-align: left;
margin: 0 50px;
padding: 0.5em 1ex 0.1em;
background: #FEFFF4;
height: calc(100% - 120px);
border: 1px solid #C7C7C7;
overflow: auto; }
#usermsg {
width: calc(100% - 100px);
padding: 0.5ex;
border: 1px solid #C7C7C7; }
#submit { width: 60px; }
.error { color: #ff0000; }
#menu { padding: 12.5px 25px 12.5px 25px; }
.welcome { float: left; }
.logout { float: right; }
.msgln { margin:0 0 2px 0; }