Compare commits
34 Commits
00534c42f0
...
5adc180307
Author | SHA1 | Date |
---|---|---|
Boris | 5adc180307 | |
Boris | 2a33815c9c | |
Boris | 5f8b116aea | |
Boris | d5980664c3 | |
Boris | 57360f9c85 | |
Boris | 218abd321d | |
Boris | 2654a5d448 | |
Boris | 7e639542c1 | |
Boris | aace984e14 | |
Boris | 302da5a2be | |
Boris | ca8cb2950f | |
Boris | 045bf888c4 | |
Boris | e6285a2bca | |
Boris | 01a0e2e0eb | |
Yann Autissier | 4f1dad2ddd | |
Boris | 57f635e02f | |
Boris | 3d5f09c060 | |
Boris | 363079c2e4 | |
Boris | ab14667900 | |
Boris | 04d951a129 | |
Boris | bf34c4afe8 | |
Boris | 779eed6a37 | |
Boris | 89d60c4b12 | |
Boris | 8b0b245c34 | |
Boris | ffca895018 | |
Boris | f2886bcc8d | |
Boris | d7a6f9b49b | |
Boris | 35c5d3bec8 | |
Boris | 1205ecf37b | |
Boris | 30a80cda2c | |
Boris | 0926c2bdab | |
Boris | f61db7a385 | |
Boris | e7841d40de | |
Boris | c7c6598a52 |
|
@ -0,0 +1 @@
|
|||
.git*
|
|
@ -0,0 +1 @@
|
|||
DOCKER_SERVICE_80_TAGS=urlprefix-zeg1jeux.${APP_DOMAIN}
|
|
@ -1,2 +1,5 @@
|
|||
.env
|
||||
cache/
|
||||
tests/
|
||||
minelife.html
|
||||
vendors/keygen/__pycache__
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
MYOS ?= ../myos
|
||||
MYOS_REPOSITORY ?= https://github.com/aynicos/myos
|
||||
-include $(MYOS)/make/include.mk
|
||||
$(MYOS):
|
||||
-@git clone $(MYOS_REPOSITORY) $(MYOS)
|
||||
|
||||
ENV_VARS += DOCKER_INTERNAL_DOCKER_HOST
|
|
@ -10,3 +10,6 @@ sudo apt install python3-gpg python3-jwcrypto
|
|||
python3 -m pip install -U pgpy pynentry SecureBytes
|
||||
```
|
||||
|
||||
```
|
||||
sudo vendor/jaklis/setup.sh
|
||||
```
|
17
config.php
|
@ -8,7 +8,7 @@ error_reporting(E_ALL);
|
|||
|
||||
session_start();
|
||||
|
||||
define('DEFAULT_RADIUS', 50);
|
||||
define('DEFAULT_SEARCH_RADIUS', 50);
|
||||
|
||||
define('TAILLE_SPRITE', 32);
|
||||
define('DEMI_TAILLE_SPRITE', (TAILLE_SPRITE/2));
|
||||
|
@ -18,6 +18,8 @@ define('SONAR_DURATION', 5);
|
|||
define("LAT_ASTROPORT_ONE", 44.22484418236386);
|
||||
define("LON_ASTROPORT_ONE", 1.6395813014177014);
|
||||
|
||||
define('MAX_NEARBY_PLACES', 15);
|
||||
|
||||
class Player {
|
||||
|
||||
private $pubkey;
|
||||
|
@ -54,12 +56,6 @@ $players = [
|
|||
new Player('8PTThXiUSwwuPoqQWw3tuAn4MpvzQzpKhs6LMuiozS7Z', 'kimamila')
|
||||
];
|
||||
|
||||
if (!isset($_SESSION['radius'])) {
|
||||
|
||||
$_SESSION['radius'] = DEFAULT_RADIUS;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
=====================
|
||||
|
@ -85,7 +81,7 @@ $games = [
|
|||
]
|
||||
];
|
||||
|
||||
$radiuses = [5, 10, 20, 50];
|
||||
$radiuses = [5, 10, 20, 50, 100];
|
||||
|
||||
define('DEFAULT_GAME', 'spationaute');
|
||||
|
||||
|
@ -93,11 +89,16 @@ if (!isset($_SESSION['gameId'])) {
|
|||
|
||||
$_SESSION['gameId'] = DEFAULT_GAME;
|
||||
}
|
||||
define('GAME_JS_DIR', 'themes/'. $_SESSION['gameId'] . '/js/map');
|
||||
|
||||
|
||||
define('DEFAULT_WEBPAGE_TITLE', 'La bureautique');
|
||||
|
||||
|
||||
$javascripts = [
|
||||
'header' => [],
|
||||
'footer' => []
|
||||
];
|
||||
|
||||
require_once('functions.php');
|
||||
|
||||
|
|
|
@ -0,0 +1,98 @@
|
|||
FROM seblucas/alpine-nginx-php as dist
|
||||
LABEL maintainer aynic.os <support+docker@asycn.io>
|
||||
ARG DOCKER_BUILD_DIR
|
||||
ARG DOCKER_MACHINE=x86_64
|
||||
ARG DOCKER_SYSTEM=Linux
|
||||
|
||||
RUN apk upgrade --no-cache \
|
||||
&& apk add --no-cache \
|
||||
bash \
|
||||
ca-certificates \
|
||||
gettext \
|
||||
libc6-compat \
|
||||
libsodium \
|
||||
make \
|
||||
py3-gpgme \
|
||||
py3-pip
|
||||
|
||||
ARG IPFS_VERSION=0.16.0
|
||||
|
||||
RUN { OS="$(echo ${DOCKER_SYSTEM} |awk '{print tolower($0)}')"; \
|
||||
ARCH="$(echo ${DOCKER_MACHINE})"; \
|
||||
wget -qO - https://github.com/koalaman/shellcheck/releases/download/stable/shellcheck-stable.${OS}.${ARCH}.tar.xz \
|
||||
|tar --strip-components 1 -C /usr/local/bin -xJf - shellcheck-stable/shellcheck; } \
|
||||
&& { ARCH="$(echo ${DOCKER_MACHINE} |awk '/x86_64/ {print "amd64"}; /aarch64/ {print "arm64"}')"; \
|
||||
wget -qO - https://github.com/ipfs/kubo/releases/download/v${IPFS_VERSION}/kubo_v${IPFS_VERSION}_${OS}-${ARCH}.tar.gz \
|
||||
|tar --strip-components 1 -C /usr/local/bin -xzf - kubo/ipfs; } \
|
||||
&& mkdir -p /usr/local/lib/shellspec \
|
||||
&& wget -qO - https://github.com/shellspec/shellspec/archive/refs/heads/master.tar.gz \
|
||||
|tar --strip-components 1 -C /usr/local/lib/shellspec -xzf - \
|
||||
&& ln -s /usr/local/lib/shellspec/shellspec /usr/local/bin/shellspec
|
||||
|
||||
RUN apk add --no-cache --virtual .build-deps \
|
||||
build-base \
|
||||
cargo \
|
||||
libffi-dev \
|
||||
openssl-dev \
|
||||
py3-wheel \
|
||||
python3-dev \
|
||||
swig \
|
||||
&& mkdir -p /usr/local/src/jaklis \
|
||||
&& wget -qO - https://github.com/aynicos/jaklis/archive/master.tar.gz \
|
||||
|tar --strip-components 1 -C /usr/local/src/jaklis -xzf - \
|
||||
&& pip3 install -r /usr/local/src/jaklis/requirements.txt \
|
||||
&& ln -s /usr/local/src/jaklis/jaklis.py /usr/local/bin/jaklis \
|
||||
&& chmod 0755 /usr/local/bin/jaklis \
|
||||
&& /usr/local/bin/jaklis --help >/dev/null \
|
||||
&& mkdir -p /usr/local/src/dpgpid \
|
||||
&& wget -qO - https://github.com/aynicos/dpgpid/archive/wip.tar.gz \
|
||||
|tar --strip-components 1 -C /usr/local/src/dpgpid -xzf - \
|
||||
&& pip3 install -r /usr/local/src/dpgpid/requirements.txt \
|
||||
&& ln -s /usr/local/src/dpgpid/keygen /usr/local/bin/keygen \
|
||||
&& chmod 0755 /usr/local/bin/keygen \
|
||||
&& /usr/local/bin/keygen --help >/dev/null \
|
||||
&& rm -rf /root/.cache \
|
||||
&& apk del --no-network .build-deps \
|
||||
&& find ./lib -type f -executable -exec scanelf --needed --nobanner --format '%n#p' '{}' ';' \
|
||||
|tr ',' '\n' \
|
||||
|sort -u \
|
||||
|awk 'system("[ -e /lib/"$1" -o -e /usr/lib/"$1" -o -e ./lib/python'"${PYTHON_RELEASE}"'/site-packages/*/"$1" ]") == 0 { next } { print "so:" $1 }' \
|
||||
|xargs -rt apk add --no-cache
|
||||
|
||||
RUN sed -i 's/^}/ location \/ { index index.php; }\n}/' /etc/nginx/http.d/default.conf
|
||||
|
||||
FROM dist as master
|
||||
ARG DOCKER_BUILD_DIR
|
||||
ARG DOCKER_GID
|
||||
ARG SHELL=/bin/bash
|
||||
ARG UID
|
||||
ARG USER
|
||||
ENV UID=${UID}
|
||||
ENV GID=${UID}
|
||||
ENV USER=nginx
|
||||
|
||||
# If we provide a numeric UID
|
||||
RUN [ "$UID" -eq "$UID" ] 2>/dev/null \
|
||||
# Remove user with $UID if it is not our $USER
|
||||
&& if [ "$(getent passwd $UID |awk -F: '{print $1}')" != "$USER" ]; then \
|
||||
sed -i '/^'$(getent passwd $UID |awk -F: '{print $1}')':x:'$UID':/d' /etc/passwd; \
|
||||
sed -i '/^'$(getent group $GID |awk -F: '{print $1}')':x:'$GID':/d' /etc/group; \
|
||||
fi \
|
||||
# Force $UID if our $USER already exists
|
||||
&& sed -i 's/^'$USER':x:[0-9]\+:[0-9]\+:/'$USER':x:'$UID':'$GID':/' /etc/passwd \
|
||||
&& sed -i 's/^'$USER':x:[0-9]\+:/'$USER':x:'$GID':/' /etc/group \
|
||||
# Create $USER if it does not exist
|
||||
&& if [ "$(getent passwd $UID)" = "" ]; then \
|
||||
echo "$USER:x:$UID:$GID::/home/$USER:$SHELL" >> /etc/passwd; \
|
||||
echo "$USER:\!:$(($(date +%s) / 60 / 60 / 24)):0:99999:7:::" >> /etc/shadow; \
|
||||
echo "$USER:x:$GID:" >> /etc/group; \
|
||||
fi \
|
||||
&& mkdir -p /home/$USER \
|
||||
&& chown $UID:$GID /home/$USER \
|
||||
|| true
|
||||
|
||||
ENV SHELL=${SHELL}
|
||||
WORKDIR /var/www
|
||||
|
||||
RUN rm /etc/php7/conf.d/00_opcache.ini
|
||||
RUN sed -i 's/^;php_flag[display_errors] = off/php_flag[display_errors] = on/' /etc/php7/php-fpm.d/www.conf
|
|
@ -0,0 +1,25 @@
|
|||
version: '3.6'
|
||||
|
||||
services:
|
||||
docker:
|
||||
environment:
|
||||
- ENV=${ENV}
|
||||
- SHELL=${DOCKER_SHELL}
|
||||
labels:
|
||||
- SERVICE_80_CHECK_HTTP=/
|
||||
- SERVICE_80_NAME=${COMPOSE_SERVICE_NAME}-docker-80
|
||||
- SERVICE_80_TAGS=${DOCKER_SERVICE_80_TAGS}
|
||||
networks:
|
||||
- private
|
||||
- public
|
||||
extra_hosts:
|
||||
- astroport.localhost:${DOCKER_INTERNAL_DOCKER_HOST}
|
||||
|
||||
|
||||
networks:
|
||||
private:
|
||||
external: true
|
||||
name: ${DOCKER_NETWORK_PRIVATE}
|
||||
public:
|
||||
external: true
|
||||
name: ${DOCKER_NETWORK_PUBLIC}
|
|
@ -0,0 +1,34 @@
|
|||
version: '3.6'
|
||||
|
||||
services:
|
||||
docker:
|
||||
build:
|
||||
args:
|
||||
- DOCKER_BUILD_DIR=docker
|
||||
- GID=${GID}
|
||||
- IPFS_VERSION=${IPFS_VERSION:-0.16.0}
|
||||
- UID=${UID}
|
||||
- USER=${USER}
|
||||
context: ../
|
||||
dockerfile: docker/Dockerfile
|
||||
ports:
|
||||
- 80
|
||||
restart: always
|
||||
volumes:
|
||||
- ipfs:${HOME}/.ipfs:cached,ro
|
||||
- data:/var/www:delegated
|
||||
working_dir: /var/www
|
||||
|
||||
volumes:
|
||||
ipfs:
|
||||
driver: local
|
||||
driver_opts:
|
||||
type: none
|
||||
device: ${HOME}/.ipfs
|
||||
o: bind
|
||||
data:
|
||||
driver: local
|
||||
driver_opts:
|
||||
type: none
|
||||
device: ${APP_DIR:-.}
|
||||
o: bind
|
|
@ -0,0 +1,30 @@
|
|||
<?php
|
||||
|
||||
require_once('config.php');
|
||||
require_once('lib/Gchange.class.php');
|
||||
|
||||
$gchange = new Gchange();
|
||||
|
||||
$javascripts['header'][] = 'lib/js/farfetched.js';
|
||||
|
||||
$bodyIds = 'farfetched';
|
||||
include_once('header.php');
|
||||
|
||||
?>
|
||||
|
||||
<section id="shippable">
|
||||
|
||||
<h2>Envoi possible</h2>
|
||||
<ul id="shippable-offers" class="offers-list">
|
||||
</ul>
|
||||
</section>
|
||||
|
||||
<section id="immaterial">
|
||||
<h2>Offres immatérielles</h2>
|
||||
<ul id="immaterial-offers" class="offers-list">
|
||||
</ul>
|
||||
</section>
|
||||
|
||||
<?php
|
||||
|
||||
include_once('footer.php');
|
28
footer.php
|
@ -5,22 +5,28 @@
|
|||
</footer>
|
||||
|
||||
<?php
|
||||
if (isset($_SESSION['gameId']) and isset($bodyIds) and strpos($bodyIds, 'startpage') === false) {
|
||||
|
||||
$themeJSDir = 'themes/'. $_SESSION['gameId'] . '/js';
|
||||
$files = scandir($themeJSDir);
|
||||
$files = array_slice($files, 2);
|
||||
// if (isset($_SESSION['gameId']) and ((isset($bodyIds) and strpos($bodyIds, 'startpage') === false)) or (!isset($bodyIds))) {
|
||||
|
||||
foreach ($files as $f) {
|
||||
// $themeJSDir = 'themes/'. $_SESSION['gameId'] . '/js';
|
||||
// $files = scandir($themeJSDir);
|
||||
// $files = array_slice($files, 2);
|
||||
|
||||
echo '
|
||||
<script type="text/javascript" src="'. $themeJSDir . '/' . $f .'"></script>
|
||||
';
|
||||
}
|
||||
// foreach ($files as $f) {
|
||||
|
||||
// echo '
|
||||
// <script type="text/javascript" src="'. $themeJSDir . '/' . $f .'"></script>
|
||||
// ';
|
||||
// }
|
||||
// }
|
||||
|
||||
foreach ($javascripts['footer'] as $js) {
|
||||
|
||||
echo '
|
||||
<script src="'. $js . '"></script>
|
||||
';
|
||||
}
|
||||
?>
|
||||
|
||||
<script type="text/javascript" src="assets/js/places.js"></script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
11
header.php
|
@ -8,7 +8,7 @@ $webpageTitle = isset($webpageTitle) ? $webpageTitle : DEFAULT_WEBPAGE_TITLE;
|
|||
<title><?php echo $webpageTitle; ?></title>
|
||||
|
||||
<?php
|
||||
if (isset($_SESSION['gameId']) and isset($bodyIds) and strpos($bodyIds, 'startpage') === false) {
|
||||
if (isset($_SESSION['gameId']) and ((isset($bodyIds) and strpos($bodyIds, 'startpage') === false)) or (!isset($bodyIds))) {
|
||||
|
||||
$themeCSSDir = 'themes/'. $_SESSION['gameId'] . '/css';
|
||||
$files = scandir($themeCSSDir);
|
||||
|
@ -26,6 +26,15 @@ $webpageTitle = isset($webpageTitle) ? $webpageTitle : DEFAULT_WEBPAGE_TITLE;
|
|||
<link rel="stylesheet" type="text/css" href="themes/deco.css" />
|
||||
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
|
||||
<?php
|
||||
foreach ($javascripts['header'] as $js) {
|
||||
|
||||
echo '
|
||||
<script src="'. $js . '"></script>
|
||||
';
|
||||
}
|
||||
?>
|
||||
</head>
|
||||
<?php
|
||||
$bodyIds = !isset($bodyIds) ? '' : ' id="'. $bodyIds .'"';
|
||||
|
|
63
home.php
|
@ -1,11 +1,50 @@
|
|||
<?php
|
||||
|
||||
require_once('config.php');
|
||||
require_once('lib/Gchange.class.php');
|
||||
require_once('lib/Keygen.class.php');
|
||||
require_once('lib/Fred.class.php');
|
||||
|
||||
$bodyIds = 'home';
|
||||
include_once('header.php');
|
||||
|
||||
$gchange = new Gchange();
|
||||
|
||||
$keygen = new Keygen();
|
||||
|
||||
// $ipfsHost = 'http://astroport.localhost:8080';
|
||||
$ipfsHost = 'http://libra.copylaradio.com:8080';
|
||||
|
||||
|
||||
try {
|
||||
|
||||
$player = $gchange->getUser($_SESSION['player_pubkey']);
|
||||
|
||||
|
||||
} catch (Exception $errMsg) {
|
||||
|
||||
ErrorsHandler::kaput($errMsg);
|
||||
}
|
||||
|
||||
try {
|
||||
|
||||
$twLink = $ipfsHost . '/ipns/' . $keygen->getIPNSPub($_SESSION['salt'], $_SESSION['pepper']);
|
||||
|
||||
} catch (Exception $errMsg) {
|
||||
|
||||
$twLink = '#';
|
||||
$fred = new Fred();
|
||||
$twLink = $ipfsHost . '/ipns/' . $fred->donneMoiLaPutainDeClefIPNS($_SESSION['salt'], $_SESSION['pepper']);
|
||||
|
||||
}
|
||||
|
||||
|
||||
echo '
|
||||
<header>
|
||||
Bienvenue '. $player->getUserName() . ' !
|
||||
<!-- ('. substr($player->getUserGchangeId(), 0, 8) . ') -->
|
||||
</header>
|
||||
|
||||
<nav>
|
||||
<ul>
|
||||
<li id="dashboard-map">
|
||||
|
@ -23,6 +62,30 @@ echo '
|
|||
</span>
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<li id="dashboard-farfetched">
|
||||
<a href="farfetched.php">
|
||||
<span>
|
||||
À distance ou en livraison
|
||||
</span>
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<li id="dashboard-minelife">
|
||||
<a href="minelife/index.html">
|
||||
<span>
|
||||
Manuel
|
||||
</span>
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<li id="dashboard-tiddlywiki">
|
||||
<a href="'. $twLink .'">
|
||||
<span>
|
||||
'. ('Mon TiddlyWiki') .'
|
||||
</span>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@ require_once('Message.class.php');
|
|||
|
||||
function compareMsgDate ($msg1, $msg2) {
|
||||
|
||||
return ($msg1->getDate() < $msg2->getDate()) ? false : true;
|
||||
return ($msg1->getDate() < $msg2->getDate()) ? -1 : 1;
|
||||
}
|
||||
|
||||
class Conversation {
|
||||
|
|
|
@ -75,14 +75,14 @@ class DAO {
|
|||
|
||||
'duniter' => 2,
|
||||
'cesiumplus' => 5,
|
||||
'gchange' => 10,
|
||||
'gchange' => 1,
|
||||
];
|
||||
|
||||
private $nodeTimeoutIncrement = [
|
||||
|
||||
'duniter' => 2,
|
||||
'cesiumplus' => 10,
|
||||
'gchange' => 10
|
||||
'gchange' => 3
|
||||
];
|
||||
|
||||
private $node = NULL;
|
||||
|
@ -115,8 +115,8 @@ class DAO {
|
|||
if (!in_array($unit, $this->units)) {
|
||||
|
||||
$out = [];
|
||||
$out[] = _('L\'unité renseignée n\'existe pas.');
|
||||
$out[] = _('Vérifiez votre synthaxe.');
|
||||
$out[] = 'L\'unité renseignée n\'existe pas.';
|
||||
$out[] = 'Vérifiez votre synthaxe.';
|
||||
|
||||
$this->decease($out);
|
||||
|
||||
|
@ -205,7 +205,7 @@ class DAO {
|
|||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>'. _('Erreur critique') . '</title>
|
||||
<title>'. ('Erreur critique') . '</title>
|
||||
|
||||
<style>
|
||||
|
||||
|
@ -251,16 +251,16 @@ class DAO {
|
|||
|
||||
if ($this->displayType == 'img') {
|
||||
|
||||
return _('DUĞ1');
|
||||
return ('DUĞ1');
|
||||
|
||||
} else {
|
||||
|
||||
return _('DU<sub>Ğ1</sub>');
|
||||
return ('DU<sub>Ğ1</sub>');
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
return _('Ğ1');
|
||||
return ('Ğ1');
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -476,20 +476,22 @@ class DAO {
|
|||
if (empty($json)) {
|
||||
|
||||
$out = [];
|
||||
$out[] = _('Aucun noeud '. $nodeType .' n\'a été trouvé ou la requête n\'a pas abouti.');
|
||||
$out[] = _('Noeud interrogés : ');
|
||||
$out[] = ('Aucun noeud '. $nodeType .' n\'a été trouvé ou la requête n\'a pas abouti.');
|
||||
$out[] = ('Noeud interrogés : ');
|
||||
|
||||
$out = array_merge($out, $nodes);
|
||||
|
||||
$out[] = _('URI: ' . $uri);
|
||||
$out[] = ('URI: ' . $uri);
|
||||
|
||||
if (isset($queryParams)) {
|
||||
|
||||
$out[] = _('Paramètres de la requête : ');
|
||||
$out[] = ('Paramètres de la requête : ');
|
||||
$out[] = '<pre>'. print_r($queryParams, true) . '<pre>';
|
||||
}
|
||||
|
||||
$this->decease($out);
|
||||
// $this->decease($out);
|
||||
|
||||
throw new Exception(implode("\n", $out));
|
||||
}
|
||||
|
||||
return $json;
|
||||
|
|
|
@ -0,0 +1,64 @@
|
|||
<?php
|
||||
|
||||
class ErrorsHandler {
|
||||
|
||||
public function __construct () {
|
||||
|
||||
}
|
||||
|
||||
static public function kaput ($errorMsgs) {
|
||||
|
||||
|
||||
ob_get_clean(); // to prevent error message to display inside an HTML container (case of error generated by get method calls)
|
||||
|
||||
|
||||
if (!is_array($errorMsgs)) {
|
||||
|
||||
$errorMsgs = explode("\n", $errorMsgs);
|
||||
}
|
||||
|
||||
echo '<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>Erreur critique</title>
|
||||
|
||||
<style>
|
||||
|
||||
div {
|
||||
|
||||
overflow: auto;
|
||||
word-wrap: break-word;
|
||||
background-color: hsl(0, 100%, 69%);
|
||||
color: hsl(0, 100%, 19%);
|
||||
margin: 1em;
|
||||
padding: 1em;
|
||||
border-radius: 1em;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: calc(100% - 4em);
|
||||
max-height: calc(100vh - 4em);
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div>';
|
||||
|
||||
|
||||
foreach ($errorMsgs as $msg) {
|
||||
|
||||
echo '<pre>' . print_r($msg, true) . '</pre>';
|
||||
}
|
||||
|
||||
echo '
|
||||
</div>
|
||||
</body>
|
||||
</html>';
|
||||
|
||||
die;
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -1,39 +1,84 @@
|
|||
<?php
|
||||
|
||||
class Fred {
|
||||
|
||||
|
||||
private $gatewayProtocol = 'http';
|
||||
|
||||
private $gatewayDomain = 'libra.copylaradio.com';
|
||||
// private $gatewayDomain = 'aries.copylaradio.com';
|
||||
// private $gatewayDomain = 'astroport.localhost';
|
||||
|
||||
private $gatewayPort = '1234';
|
||||
|
||||
private $gatewayDelay = 3;
|
||||
|
||||
private $gatewayMaxRounds = 20;
|
||||
|
||||
public function __construct () {
|
||||
|
||||
}
|
||||
|
||||
public function donneMoiLAdresseIPDuServeurQuiHebergeMonTiddlyWiki ($salt, $pepper) {
|
||||
|
||||
}
|
||||
|
||||
public function donneMoiLaPutainDeClefIPNS ($prenomNom, $nomDuChienSuivieDeLaDateDeNaissanceDeJohnnyHallyday) {
|
||||
|
||||
$salt = $prenomNom;
|
||||
$pepper = $nomDuChienSuivieDeLaDateDeNaissanceDeJohnnyHallyday;
|
||||
|
||||
$query = 'salt='. $salt .'&pepper='. $pepper;
|
||||
$query = 'salt='. urlencode($salt) .'&pepper='. urlencode($pepper) . '&getipns=on';
|
||||
|
||||
$page1 = file_get_contents($this->gatewayProtocol . '://'. $this->gatewayDomain .':' . $this->gatewayPort . '/?' . $query);
|
||||
|
||||
if (empty($page1)) {
|
||||
|
||||
throw new Exception("J'ai pas pû récupérer la putain de première page.");
|
||||
}
|
||||
|
||||
$page1 = @file_get_contents($this->gatewayProtocol . '://'. $this->gatewayDomain .':' . $this->gatewayPort . '/?' . $query)
|
||||
or die('<p>On a fait du sale.</p>');
|
||||
|
||||
preg_match("`url='([^']+)'`isU", $page1, $matches);
|
||||
|
||||
$url = $matches[1];
|
||||
$url .= '/?'. $query;
|
||||
|
||||
// die($url);
|
||||
$opts2 = array(
|
||||
'http'=>array(
|
||||
'method'=>"GET",
|
||||
'header'=>"Accept-language: fr\r\n",
|
||||
'follow_location' => 0
|
||||
)
|
||||
);
|
||||
|
||||
// echo 'fred 2';
|
||||
|
||||
$context2 = stream_context_create($opts2);
|
||||
|
||||
$page2 = false;
|
||||
$rounds = 0;
|
||||
|
||||
while (($page2 === false) and $rounds < $this->gatewayMaxRounds) {
|
||||
|
||||
sleep($this->gatewayDelay);
|
||||
// echo "\n\n\nround n°" . $rounds . "\n";
|
||||
|
||||
$page2 = @file_get_contents($url, false, $context2);
|
||||
|
||||
// echo '<pre>'. print_r(htmlspecialchars($page2), true) . '</pre>';
|
||||
|
||||
$rounds++;
|
||||
}
|
||||
|
||||
sleep($this->gatewayDelay);
|
||||
if ($page2 === false) {
|
||||
|
||||
$page2 = @file_get_contents($url)
|
||||
or die('</p>On a chié dans la colle.</p>');
|
||||
throw new Exception("J'ai pas pû me connecter à ". $url ." pour récupérer la putain de deuxième page.");
|
||||
|
||||
} else if (empty($page2)) {
|
||||
|
||||
preg_match("`url='.*/ipns/([^']+)'`isU", $page2, $matches);
|
||||
throw new Exception("J'ai pas pû récupérer la putain de deuxième page.");
|
||||
}
|
||||
|
||||
preg_match("`/ipns/(.+)`is", $page2, $matches);
|
||||
|
||||
$ipnsKey = $matches[1];
|
||||
|
||||
|
@ -52,8 +97,12 @@ class Fred {
|
|||
|
||||
// echo '<pre>'; var_dump(htmlspecialchars($url)); echo '</pre>';
|
||||
|
||||
$page1 = file_get_contents($url)
|
||||
or die('<p>On a fait du sale.</p>');
|
||||
$page1 = file_get_contents($url);
|
||||
|
||||
if (empty($page1)) {
|
||||
|
||||
throw new Exception("J'ai pas pû récupérer la putain de première page.");
|
||||
}
|
||||
|
||||
// echo '<pre>'; var_dump(htmlspecialchars($page1)); echo '</pre>';
|
||||
|
||||
|
@ -64,11 +113,19 @@ class Fred {
|
|||
// echo '<pre>'; var_dump($url); echo '</pre>';
|
||||
|
||||
$page2 = '';
|
||||
$rounds = 0;
|
||||
|
||||
while (empty($page2)) {
|
||||
while (empty($page2) and $rounds < $this->gatewayMaxRounds) {
|
||||
|
||||
sleep($this->gatewayDelay);
|
||||
$page2 = @file_get_contents($url);
|
||||
$page2 = file_get_contents($url);
|
||||
|
||||
$rounds++;
|
||||
}
|
||||
|
||||
if (empty($page2)) {
|
||||
|
||||
throw new Exception("J'ai pas pû récupérer la putain de deuxième page.");
|
||||
}
|
||||
|
||||
// echo '<pre>'; var_dump(htmlspecialchars($page2)); echo '</pre>';
|
||||
|
@ -78,41 +135,76 @@ class Fred {
|
|||
return json_decode($json);
|
||||
|
||||
}
|
||||
|
||||
public function donneMoiSaPutaindeG1Pub ($prenomNom, $nomDuChienSuivieDeLaDateDeNaissanceDeJohnnyHallyday) {
|
||||
|
||||
|
||||
$salt = $prenomNom;
|
||||
$pepper = $nomDuChienSuivieDeLaDateDeNaissanceDeJohnnyHallyday;
|
||||
|
||||
$query = 'salt='. $salt .'&pepper='. $pepper . '&g1pub=on';
|
||||
$query = 'salt='. urlencode($salt) .'&pepper='. urlencode($pepper) . '&g1pub=on';
|
||||
|
||||
$url = $this->gatewayProtocol . '://'. $this->gatewayDomain .':' . $this->gatewayPort . '/?' . $query;
|
||||
|
||||
// echo '<pre>'; var_dump(htmlspecialchars($url)); echo '</pre>';
|
||||
|
||||
$page1 = file_get_contents($url)
|
||||
or die('<p>On a fait du sale.</p>');
|
||||
$opts = array(
|
||||
'http'=>array(
|
||||
'method'=>"GET",
|
||||
'header'=>"Accept-language: fr\r\n",
|
||||
'follow_location' => 0
|
||||
)
|
||||
);
|
||||
|
||||
$context = stream_context_create($opts);
|
||||
|
||||
$page1 = file_get_contents($url, false, $context);
|
||||
|
||||
|
||||
if (empty($page1)) {
|
||||
|
||||
throw new Exception("J'ai pas pû récupérer la putain de première page.");
|
||||
}
|
||||
|
||||
// die('<pre>' . htmlspecialchars($page1) . '</pre>');
|
||||
|
||||
preg_match("`url='([^']+)'`isU", $page1, $matches);
|
||||
|
||||
// die(
|
||||
// '<pre>' . htmlspecialchars($page1) . '</pre>' .
|
||||
// '<pre>' . print_r($matches, true) . '</pre>'
|
||||
// '<pre>' . htmlspecialchars($page1) . '</pre>' .
|
||||
// '<pre>' . print_r($matches, true) . '</pre>'
|
||||
// );
|
||||
|
||||
$url = $matches[1];
|
||||
|
||||
// die('<pre>' . var_dump($url, true) . '</pre>');
|
||||
|
||||
$opts2 = array(
|
||||
'http'=>array(
|
||||
'method'=>"GET",
|
||||
'header'=>"Accept-language: fr\r\n",
|
||||
'follow_location' => 0
|
||||
)
|
||||
);
|
||||
|
||||
$context2 = stream_context_create($opts2);
|
||||
|
||||
$page2 = '';
|
||||
|
||||
while (empty($page2)) {
|
||||
$rounds = 0;
|
||||
|
||||
while (empty($page2) and $rounds < $this->gatewayMaxRounds) {
|
||||
|
||||
sleep($this->gatewayDelay);
|
||||
|
||||
$page2 = @file_get_contents($url);
|
||||
$page2 = file_get_contents($url, false, $context2);
|
||||
|
||||
$rounds++;
|
||||
}
|
||||
|
||||
if (empty($page2)) {
|
||||
|
||||
throw new Exception("J'ai pas pû récupérer la putain de deuxième page.");
|
||||
}
|
||||
|
||||
preg_match("`url='.*/user/([^']+)/'`isU", $page2, $matches);
|
||||
|
@ -120,6 +212,5 @@ class Fred {
|
|||
$gchangeId = $matches[1];
|
||||
|
||||
return $gchangeId;
|
||||
|
||||
}
|
||||
}
|
|
@ -7,6 +7,7 @@ require_once('DAO.class.php');
|
|||
require_once('GchangeUser.class.php');
|
||||
require_once('GchangeRecord.class.php');
|
||||
require_once('GchangeRating.class.php');
|
||||
require_once('ErrorsHandler.class.php');
|
||||
|
||||
class Gchange {
|
||||
|
||||
|
@ -18,9 +19,13 @@ class Gchange {
|
|||
|
||||
private $cacheLongevity = array(
|
||||
'placesNearby' => 604800, // 3 jours
|
||||
'placeDetails' => 2116800, // 7 jours
|
||||
'placeVisitors' => 2116800, // 7 jours
|
||||
|
||||
'usersNearby' => 43200, // 12 heures
|
||||
'users' => 43200, // 12 heures
|
||||
'records' => 900 // 15 min
|
||||
'users' => 2116800, // 12 heures
|
||||
|
||||
'userRecords' => 900 // 15 min
|
||||
);
|
||||
|
||||
public function __construct () {
|
||||
|
@ -28,71 +33,21 @@ class Gchange {
|
|||
$this->dao = DAO::getInstance();
|
||||
}
|
||||
|
||||
public function getRecordsByIssuer ($issuer) {
|
||||
public function fetchJson ($uri, $queryParams = null) {
|
||||
|
||||
try {
|
||||
|
||||
$recordsCacheDir = 'records/user/';
|
||||
$recordsCacheFile = $issuer . '.json';
|
||||
$json = $this->dao->fetchJson($uri, 'gchange', $queryParams);
|
||||
|
||||
$json = $this->getJsonFromCache($recordsCacheDir, $recordsCacheFile, $this->cacheLongevity['records']);
|
||||
} catch (Exception $errorMsgs) {
|
||||
|
||||
if (empty($json)) {
|
||||
|
||||
$n = 20;
|
||||
|
||||
$queryParams = [
|
||||
'size' => $n,
|
||||
'query' => [
|
||||
'bool' => [
|
||||
'filter' => [
|
||||
'term' => [
|
||||
'issuer' => $issuer
|
||||
]
|
||||
|
||||
/*
|
||||
, 'range' => [
|
||||
'stock' => [
|
||||
'gte' => 1
|
||||
]
|
||||
]
|
||||
*/
|
||||
]
|
||||
/*
|
||||
, 'filter' => [
|
||||
]
|
||||
*/
|
||||
|
||||
, 'must_not' => [
|
||||
[ "term" => ["stock" => 0] ]
|
||||
]
|
||||
|
||||
]
|
||||
],
|
||||
'sort' => [
|
||||
['time' => 'desc']
|
||||
]
|
||||
];
|
||||
|
||||
$json = $this->dao->fetchJson('/market/record/_search', 'gchange', $queryParams);
|
||||
|
||||
$this->cacheJson($recordsCacheDir, $recordsCacheFile, $json);
|
||||
throw $errorMsgs;
|
||||
}
|
||||
|
||||
$result = json_decode($json);
|
||||
|
||||
|
||||
$records = [];
|
||||
|
||||
foreach ($result->hits->hits as $hit) {
|
||||
|
||||
$records[] = new GchangeRecord($hit);
|
||||
}
|
||||
|
||||
return $records;
|
||||
|
||||
return $json;
|
||||
}
|
||||
|
||||
private function getJsonFromCache ($dir, $file, $cacheLongevity) {
|
||||
private function getJsonFromCache ($dir, $file, $cacheLongevity = null) {
|
||||
|
||||
if (!$this->isActivatedCache) {
|
||||
|
||||
|
@ -103,13 +58,30 @@ class Gchange {
|
|||
$json = null;
|
||||
$jsonFullPath = $this->cacheDir . $dir . $file;
|
||||
|
||||
if (file_exists($jsonFullPath) and ((time() - filemtime($jsonFullPath)) < $cacheLongevity)) {
|
||||
|
||||
$json = file_get_contents($jsonFullPath);
|
||||
if (!file_exists($jsonFullPath)) {
|
||||
|
||||
throw new Exception("Le fichier de cache suivant n'existe pas : " . $jsonFullPath);
|
||||
|
||||
}
|
||||
|
||||
return $json;
|
||||
if ($cacheLongevity !== null and (time() - filemtime($jsonFullPath) > $cacheLongevity)) {
|
||||
|
||||
throw new Exception("Le fichier de cache est expiré.");
|
||||
}
|
||||
|
||||
|
||||
try {
|
||||
|
||||
$json = file_get_contents($jsonFullPath);
|
||||
|
||||
} catch (Exception $errorMsgs) {
|
||||
|
||||
throw new Exception($jsonFullPath . " n'a pas été trouvé");
|
||||
|
||||
} finally {
|
||||
|
||||
return $json;
|
||||
}
|
||||
}
|
||||
|
||||
private function cacheJson ($dir, $file, $json) {
|
||||
|
@ -136,13 +108,30 @@ class Gchange {
|
|||
$usersCacheDir = 'users/';
|
||||
$usersCacheFile = $pubkey . '.json';
|
||||
|
||||
$json = $this->getJsonFromCache($usersCacheDir, $usersCacheFile, $this->cacheLongevity['users']);
|
||||
try {
|
||||
|
||||
if (empty($json)) {
|
||||
$json = $this->getJsonFromCache($usersCacheDir, $usersCacheFile, $this->cacheLongevity['users']);
|
||||
|
||||
$json = $this->dao->fetchJson(('/user/profile/'. $pubkey), 'gchange');
|
||||
|
||||
$this->cacheJson($usersCacheDir, $usersCacheFile, $json);
|
||||
} catch (Exception $errorMsgs) {
|
||||
|
||||
try {
|
||||
|
||||
$json = $this->fetchJson('/user/profile/'. $pubkey);
|
||||
|
||||
$this->cacheJson($usersCacheDir, $usersCacheFile, $json);
|
||||
|
||||
} catch (Exception $errorMsgs) {
|
||||
|
||||
try {
|
||||
|
||||
$json = $this->getJsonFromCache($usersCacheDir, $usersCacheFile, null);
|
||||
|
||||
} catch (Exception $errorMsgs) {
|
||||
|
||||
throw new Exception("L'utilisateur " . $pubkey . " n'a été trouvé nulle part.");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
$result = json_decode($json);
|
||||
|
@ -150,63 +139,50 @@ class Gchange {
|
|||
return new GchangeUser($result);
|
||||
}
|
||||
|
||||
public function getPlacesNearUser ($user, $radius) {
|
||||
|
||||
return $this->getNearbyPlaces($user->getLat(), $user->getLon(), $radius);
|
||||
|
||||
/*
|
||||
$placesCacheDir = 'places-nearby/user/';
|
||||
$placesCacheFile = $user->getUserGchangeId() . '.json';
|
||||
|
||||
$json = $this->getJsonFromCache($placesCacheDir, $placesCacheFile, $this->cacheLongevity['placesNearby']);
|
||||
|
||||
if (empty($json)) {
|
||||
|
||||
$json = $this->getNearbyPlacesJson($user->getLat(), $user->getLon(), $radius);
|
||||
|
||||
$this->cacheJson($placesCacheDir, $placesCacheFile, $json);
|
||||
|
||||
}
|
||||
|
||||
$result = json_decode($json);
|
||||
|
||||
return $result->hits->hits;
|
||||
|
||||
*/
|
||||
}
|
||||
|
||||
public function getNearbyPlaces ($lat, $lon, $maxDistance, $minDistance = NULL) {
|
||||
|
||||
$placesCacheDir = 'places-nearby/geopoint/';
|
||||
$placesCacheFile = $lat . ',' . $lon . '.json';
|
||||
|
||||
$json = $this->getJsonFromCache($placesCacheDir, $placesCacheFile, $this->cacheLongevity['placesNearby']);
|
||||
|
||||
if (empty($json)) {
|
||||
|
||||
$json = $this->getNearbyPlacesJson($lat, $lon, $maxDistance, $minDistance);
|
||||
|
||||
$this->cacheJson($placesCacheDir, $placesCacheFile, $json);
|
||||
|
||||
}
|
||||
|
||||
$result = json_decode($json);
|
||||
|
||||
return $result->hits->hits;
|
||||
}
|
||||
|
||||
public function getNearbyUsers ($lat, $lon, $maxDistance, $minDistance = NULL) {
|
||||
|
||||
$placesCacheDir = 'users-nearby/geopoint/';
|
||||
$placesCacheFile = $lat . ',' . $lon . '.json';
|
||||
$nearbyUsersCacheDir = 'users-nearby/geopoint/' . $maxDistance . 'km/';
|
||||
$nearbyUsersCacheFile = $lat . ',' . $lon . '.json';
|
||||
|
||||
$json = $this->getJsonFromCache($placesCacheDir, $placesCacheFile, $this->cacheLongevity['usersNearby']);
|
||||
try {
|
||||
|
||||
if (empty($json)) {
|
||||
$json = $this->getJsonFromCache($nearbyUsersCacheDir, $nearbyUsersCacheFile, $this->cacheLongevity['usersNearby']);
|
||||
|
||||
} catch (Exception $errorMsgs) {
|
||||
|
||||
$n = 20;
|
||||
|
||||
$json = $this->getNearbyPlacesJson($lat, $lon, $maxDistance, $minDistance);
|
||||
$queryParams = [
|
||||
'size' => $n,
|
||||
'query' => [
|
||||
'bool' => [
|
||||
'filter' => [
|
||||
[
|
||||
'geo_distance' => [
|
||||
|
||||
"distance" => $maxDistance . 'km',
|
||||
"geoPoint"=> [
|
||||
"lat" => $lat,
|
||||
"lon" => $lon
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
];
|
||||
|
||||
$this->cacheJson($placesCacheDir, $placesCacheFile, $json);
|
||||
try {
|
||||
|
||||
$json = $this->fetchJson('/users/record/_search', $queryParams);
|
||||
|
||||
$this->cacheJson($nearbyUsersCacheDir, $nearbyUsersCacheFile, $json);
|
||||
|
||||
} catch (Exception $errorMsgs) {
|
||||
|
||||
$json = $this->getJsonFromCache($nearbyUsersCacheDir, $nearbyUsersCacheFile, null);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
@ -214,26 +190,217 @@ class Gchange {
|
|||
|
||||
return $result->hits->hits;
|
||||
}
|
||||
|
||||
public function getPlacesNearUser ($user, $radius, $maxPlacesNb) {
|
||||
|
||||
return $this->getNearbyPlaces($user->getLat(), $user->getLon(), $radius, null, $maxPlacesNb);
|
||||
}
|
||||
|
||||
public function getNearbyPlaces ($lat, $lon, $maxDistance, $minDistance = NULL, $maxPlacesNb = 15) {
|
||||
|
||||
$placesCacheDir = 'places-nearby/geopoint/' . $maxDistance . 'km/';
|
||||
$placesCacheFile = $lat . ',' . $lon . '.json';
|
||||
|
||||
$placeDetailsCacheDir = 'place/details/';
|
||||
|
||||
$nearbyPlaces = [];
|
||||
|
||||
try {
|
||||
|
||||
$json = $this->getJsonFromCache($placesCacheDir, $placesCacheFile, $this->cacheLongevity['placesNearby']);
|
||||
|
||||
$places = json_decode($json);
|
||||
|
||||
foreach ($places->hits->hits as $place) {
|
||||
|
||||
try {
|
||||
|
||||
$p = $this->getPlaceDetails($place->_id);
|
||||
$nearbyPlaces[] = $p;
|
||||
|
||||
} catch (Exception $errorMsgs) {
|
||||
|
||||
// place not found
|
||||
}
|
||||
}
|
||||
|
||||
} catch (Exception $errorMsgs) {
|
||||
|
||||
try {
|
||||
|
||||
$n = (string) $maxPlacesNb;
|
||||
|
||||
$queryParams = [
|
||||
'size' => $n,
|
||||
'query' => [
|
||||
'bool' => [
|
||||
'filter' => [
|
||||
[
|
||||
'geo_distance' => [
|
||||
|
||||
"distance" => $maxDistance . 'km',
|
||||
"geoPoint"=> [
|
||||
"lat" => $lat,
|
||||
"lon" => $lon
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
];
|
||||
|
||||
$json = $this->fetchJson('/page/record/_search', $queryParams);
|
||||
|
||||
$result = json_decode($json);
|
||||
|
||||
$resultClone = $this->filterIds($result);
|
||||
|
||||
// cache nearby places index
|
||||
$this->cacheJson($placesCacheDir, $placesCacheFile, json_encode($resultClone));
|
||||
|
||||
// cache each nearby place details
|
||||
|
||||
// ob_get_clean();
|
||||
// echo '<pre>'; print_r($resultClone); echo '</pre>';
|
||||
// echo '<pre>'; print_r($result); echo '</pre>';
|
||||
foreach ($result->hits->hits as $place) {
|
||||
|
||||
$nearbyPlaces[] = $place;
|
||||
|
||||
$placeDetailsCacheFile = $place->_id . '.json';
|
||||
$this->cacheJson($placeDetailsCacheDir, $placeDetailsCacheFile, json_encode($place));
|
||||
}
|
||||
|
||||
} catch (Exception $errorMsgs) {
|
||||
|
||||
try {
|
||||
|
||||
$json = $this->getJsonFromCache($placesCacheDir, $placesCacheFile, null);
|
||||
|
||||
$result = json_decode($json);
|
||||
|
||||
foreach ($result->hits->hits as $place) {
|
||||
|
||||
try {
|
||||
|
||||
$p = $this->getPlaceDetails($place->_id);
|
||||
$nearbyPlaces[] = $p;
|
||||
|
||||
} catch (Exception $errorMsgs) {
|
||||
|
||||
// place not found
|
||||
}
|
||||
}
|
||||
|
||||
} catch (Exception $errorMsgs) {
|
||||
|
||||
throw new Exception('Pas pu récupérer la liste des lieux : ' . $errorMsgs);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $nearbyPlaces;
|
||||
}
|
||||
|
||||
private function filterIds ($r) {
|
||||
|
||||
// $result = clone $r;
|
||||
|
||||
$result = new stdClass;
|
||||
|
||||
$result->took = $r->took;
|
||||
$result->timed_out = $r->timed_out;
|
||||
$result->_shards = new stdClass;
|
||||
$result->_shards->total = $r->_shards->total;
|
||||
$result->_shards->successful = $r->_shards->successful;
|
||||
$result->_shards->failed = $r->_shards->failed;
|
||||
$result->hits = new stdClass;
|
||||
$result->hits->total = $r->hits->total;
|
||||
$result->hits->max_score = $r->hits->max_score;
|
||||
$result->hits->hits = array();
|
||||
|
||||
$rHitsNb = count($r->hits->hits);
|
||||
|
||||
for ($i = 0; $i < $rHitsNb; $i++) {
|
||||
|
||||
$result->hits->hits[$i] = new stdClass;
|
||||
|
||||
$result->hits->hits[$i]->_id = $r->hits->hits[$i]->_id;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/*
|
||||
private function filterIds (&$item) {
|
||||
|
||||
$itemId = $item->_id;
|
||||
$item = new stdClass;
|
||||
$item->_id = $itemId;
|
||||
}
|
||||
*/
|
||||
|
||||
public function getPlaceDetails ($placeId) {
|
||||
|
||||
$placeDetailsCacheDir = 'place/details/';
|
||||
$placeDetailsCacheFile = $placeId . '.json';
|
||||
|
||||
try {
|
||||
|
||||
$json = $this->getJsonFromCache($placeDetailsCacheDir, $placeDetailsCacheFile, $this->cacheLongevity['placeDetails']);
|
||||
|
||||
} catch (Exception $errorMsgs) {
|
||||
|
||||
try {
|
||||
|
||||
$json = $this->fetchJson('/page/record/' + $placeId);
|
||||
|
||||
$this->cacheJson($placeDetailsCacheDir, $placeDetailsCacheFile, $json);
|
||||
|
||||
} catch (Exception $errorMsgs) {
|
||||
|
||||
try {
|
||||
|
||||
$json = $this->getJsonFromCache($placeDetailsCacheDir, $placeDetailsCacheFile, null);
|
||||
|
||||
} catch (Exception $errorMsgs) {
|
||||
|
||||
throw new Exception('Pas pu trouver les détails pour la page ' . $placeId);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return json_decode($json);
|
||||
|
||||
}
|
||||
|
||||
|
||||
public function getImmaterialRecords () {
|
||||
/*
|
||||
public function getNearbyRecords ($lat, $lon, $maxDistance, $minDistance = NULL) {
|
||||
|
||||
$n = 20;
|
||||
|
||||
$queryParams = [
|
||||
'size' => $n,
|
||||
'query' => [
|
||||
'nested' => [
|
||||
'path' => 'category',
|
||||
'query' => [
|
||||
'bool' => [
|
||||
'should' => [
|
||||
[ 'term' => [ 'category.parent' => 'cat31' ] ],
|
||||
[ 'term' => [ 'category.id' => 'cat31' ] ],
|
||||
[ 'term' => [ 'category.parent' => 'cat74' ] ],
|
||||
[ 'term' => [ 'category.id' => 'cat74' ] ]
|
||||
],
|
||||
'must_not' => [
|
||||
[ "term" => ["category.id" => "cat65"] ]
|
||||
'bool' => [
|
||||
'must' => [
|
||||
[
|
||||
'geo_distance' => [
|
||||
|
||||
"distance" => $maxDistance . 'km',
|
||||
"geoPoint"=> [
|
||||
"lat" => $lat,
|
||||
"lon" => $lon
|
||||
]
|
||||
]
|
||||
], [
|
||||
'range' => [
|
||||
'stock' => [
|
||||
'gte' => 1
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
|
@ -241,7 +408,7 @@ class Gchange {
|
|||
]
|
||||
];
|
||||
|
||||
$json = $this->dao->fetchJson('/market/record/_search?pretty', 'gchange', $queryParams);
|
||||
$json = $this->fetchJson('/market/record/_search?pretty', $queryParams);
|
||||
$result = json_decode($json);
|
||||
|
||||
|
||||
|
@ -254,42 +421,190 @@ class Gchange {
|
|||
|
||||
return $records;
|
||||
}
|
||||
*/
|
||||
|
||||
public function getUsersInDaPlace ($placeId) {
|
||||
|
||||
$n = 20;
|
||||
$users = [];
|
||||
|
||||
$cacheDir = 'place/visitors/';
|
||||
$cacheFile = $placeId . '.json';
|
||||
$usersCacheDir = 'users/';
|
||||
|
||||
try {
|
||||
|
||||
$json = $this->getJsonFromCache($cacheDir, $cacheFile, $this->cacheLongevity['placeVisitors']);
|
||||
$result = json_decode($json);
|
||||
|
||||
foreach ($result->hits->hits as $hit) {
|
||||
|
||||
$user = null;
|
||||
|
||||
try {
|
||||
|
||||
$user = null;
|
||||
$user = $this->getUser($hit->_id);
|
||||
$users[] = $user;
|
||||
|
||||
} catch (Exception $errorMsgs) {
|
||||
|
||||
// Utilisateur non trouvé
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
$queryParams = [
|
||||
'size' => $n,
|
||||
'query' => [
|
||||
'nested' => [
|
||||
'path' => 'socials',
|
||||
'query' => [
|
||||
'bool' => [
|
||||
'filter' => [
|
||||
'term' => [
|
||||
'socials.url' => 'https://www.gchange.fr/#/app/page/view/'. $placeId .'/'
|
||||
} catch (Exception $errorMsgs) {
|
||||
|
||||
try {
|
||||
$n = 20;
|
||||
|
||||
$queryParams = [
|
||||
'size' => $n
|
||||
// ,'fields' => ['_id']
|
||||
,'query' => [
|
||||
'nested' => [
|
||||
'path' => 'socials',
|
||||
'query' => [
|
||||
'bool' => [
|
||||
'filter' => [
|
||||
'term' => [
|
||||
'socials.url' => 'https://www.gchange.fr/#/app/page/view/'. $placeId .'/'
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
];
|
||||
];
|
||||
|
||||
$json = $this->dao->fetchJson('/user/profile/_search', 'gchange', $queryParams);
|
||||
$json = $this->fetchJson('/user/profile/_search', $queryParams);
|
||||
|
||||
$result = json_decode($json);
|
||||
|
||||
foreach ($result->hits->hits as $hit) {
|
||||
|
||||
$user = new GchangeUser($hit);
|
||||
|
||||
$users[] = $user;
|
||||
|
||||
$this->cacheJson($usersCacheDir, $hit->_id . '.json', $user->jsonify());
|
||||
}
|
||||
|
||||
} catch (Exception $errorMsgs) {
|
||||
|
||||
try {
|
||||
|
||||
$json = $this->getJsonFromCache($cacheDir, $cacheFile, null);
|
||||
|
||||
$result = json_decode($json);
|
||||
|
||||
foreach ($result->hits->hits as $hit) {
|
||||
|
||||
$user = null;
|
||||
|
||||
try {
|
||||
|
||||
$user = null;
|
||||
$user = $this->getUser($hit->_id);
|
||||
$users[] = $user;
|
||||
|
||||
} catch (Exception $errorMsgs) {
|
||||
|
||||
// Utilisateur non trouvé
|
||||
}
|
||||
}
|
||||
|
||||
} catch (Exception $errorMsgs) {
|
||||
|
||||
throw new Exception('Visiteurs trouvés nulle part.');
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $users;
|
||||
}
|
||||
|
||||
public function getRecordsByIssuer ($issuer) {
|
||||
|
||||
|
||||
$recordsCacheDir = 'records/user/';
|
||||
$recordsCacheFile = $issuer . '.json';
|
||||
|
||||
try {
|
||||
|
||||
$json = $this->getJsonFromCache($recordsCacheDir, $recordsCacheFile, $this->cacheLongevity['userRecords']);
|
||||
|
||||
} catch (Exception $errorMsgs) {
|
||||
|
||||
try {
|
||||
|
||||
$n = 20;
|
||||
|
||||
$queryParams = [
|
||||
'size' => $n,
|
||||
'query' => [
|
||||
'bool' => [
|
||||
'filter' => [
|
||||
'term' => [
|
||||
'issuer' => $issuer
|
||||
]
|
||||
|
||||
/*
|
||||
, 'range' => [
|
||||
'stock' => [
|
||||
'gte' => 1
|
||||
]
|
||||
]
|
||||
*/
|
||||
]
|
||||
/*
|
||||
, 'filter' => [
|
||||
]
|
||||
*/
|
||||
|
||||
, 'must_not' => [
|
||||
[ "term" => ["stock" => 0] ]
|
||||
]
|
||||
|
||||
]
|
||||
],
|
||||
'sort' => [
|
||||
['time' => 'desc']
|
||||
]
|
||||
];
|
||||
|
||||
$json = $this->fetchJson('/market/record/_search', $queryParams);
|
||||
|
||||
$this->cacheJson($recordsCacheDir, $recordsCacheFile, $json);
|
||||
|
||||
} catch (Exception $errorMsgs) {
|
||||
|
||||
try {
|
||||
|
||||
$json = $this->getJsonFromCache($recordsCacheDir, $recordsCacheFile, null);
|
||||
|
||||
} catch (Exception $errorMsgs) {
|
||||
|
||||
throw new Exception ("Aucune annonce trouvée pour l'utilisateur " . $issuer);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
$result = json_decode($json);
|
||||
|
||||
|
||||
$users = [];
|
||||
$records = [];
|
||||
|
||||
foreach ($result->hits->hits as $hit) {
|
||||
|
||||
$users[] = new GchangeUser($hit);
|
||||
$records[] = new GchangeRecord($hit);
|
||||
}
|
||||
|
||||
return $users;
|
||||
return $records;
|
||||
|
||||
}
|
||||
|
||||
public function getRatingsSentBy ($issuer) {
|
||||
|
@ -310,7 +625,7 @@ class Gchange {
|
|||
]
|
||||
];
|
||||
|
||||
$json = $this->dao->fetchJson('/like/record/_search', 'gchange', $queryParams);
|
||||
$json = $this->fetchJson('/like/record/_search', $queryParams);
|
||||
|
||||
$result = json_decode($json);
|
||||
|
||||
|
@ -342,7 +657,7 @@ class Gchange {
|
|||
]
|
||||
];
|
||||
|
||||
$json = $this->dao->fetchJson('/like/record/_search', 'gchange', $queryParams);
|
||||
$json = $this->fetchJson('/like/record/_search', $queryParams);
|
||||
|
||||
$result = json_decode($json);
|
||||
|
||||
|
@ -355,79 +670,6 @@ class Gchange {
|
|||
|
||||
return $ratings;
|
||||
}
|
||||
|
||||
public function getNearbyPlacesJson ($lat, $lon, $maxDistance, $minDistance = NULL) {
|
||||
|
||||
$n = 20;
|
||||
|
||||
$queryParams = [
|
||||
'size' => $n,
|
||||
'query' => [
|
||||
'bool' => [
|
||||
'filter' => [
|
||||
[
|
||||
'geo_distance' => [
|
||||
|
||||
"distance" => $maxDistance . 'km',
|
||||
"geoPoint"=> [
|
||||
"lat" => $lat,
|
||||
"lon" => $lon
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
];
|
||||
|
||||
$json = $this->dao->fetchJson('/page/record/_search', 'gchange', $queryParams);
|
||||
|
||||
return $json;
|
||||
}
|
||||
|
||||
public function getNearbyRecords ($lat, $lon, $maxDistance, $minDistance = NULL) {
|
||||
|
||||
$n = 20;
|
||||
|
||||
$queryParams = [
|
||||
'size' => $n,
|
||||
'query' => [
|
||||
'bool' => [
|
||||
'must' => [
|
||||
[
|
||||
'geo_distance' => [
|
||||
|
||||
"distance" => $maxDistance . 'km',
|
||||
"geoPoint"=> [
|
||||
"lat" => $lat,
|
||||
"lon" => $lon
|
||||
]
|
||||
]
|
||||
], [
|
||||
'range' => [
|
||||
'stock' => [
|
||||
'gte' => 1
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
];
|
||||
|
||||
$json = $this->dao->fetchJson('/market/record/_search?pretty', 'gchange', $queryParams);
|
||||
$result = json_decode($json);
|
||||
|
||||
|
||||
$records = [];
|
||||
|
||||
foreach ($result->hits->hits as $hit) {
|
||||
|
||||
$records[] = new GchangeRecord($hit);
|
||||
}
|
||||
|
||||
return $records;
|
||||
}
|
||||
|
||||
public function getShippable () {
|
||||
|
||||
|
@ -442,7 +684,47 @@ class Gchange {
|
|||
]
|
||||
];
|
||||
|
||||
$json = $this->dao->fetchJson('/market/record/_search?pretty', 'gchange', $queryParams);
|
||||
$json = $this->fetchJson('/market/record/_search?pretty', $queryParams);
|
||||
$result = json_decode($json);
|
||||
|
||||
|
||||
$records = [];
|
||||
|
||||
foreach ($result->hits->hits as $hit) {
|
||||
|
||||
$records[] = new GchangeRecord($hit);
|
||||
}
|
||||
|
||||
return $records;
|
||||
}
|
||||
|
||||
public function getImmaterialRecords () {
|
||||
|
||||
$n = 20;
|
||||
|
||||
$queryParams = [
|
||||
'size' => $n,
|
||||
'query' => [
|
||||
'nested' => [
|
||||
'path' => 'category',
|
||||
'query' => [
|
||||
'bool' => [
|
||||
'should' => [
|
||||
[ 'term' => [ 'category.parent' => 'cat31' ] ],
|
||||
[ 'term' => [ 'category.id' => 'cat31' ] ],
|
||||
[ 'term' => [ 'category.parent' => 'cat74' ] ],
|
||||
[ 'term' => [ 'category.id' => 'cat74' ] ]
|
||||
],
|
||||
'must_not' => [
|
||||
[ "term" => ["category.id" => "cat65"] ]
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
];
|
||||
|
||||
$json = $this->fetchJson('/market/record/_search?pretty', $queryParams);
|
||||
$result = json_decode($json);
|
||||
|
||||
|
||||
|
@ -459,10 +741,5 @@ class Gchange {
|
|||
public function getHousingOffers () {
|
||||
|
||||
|
||||
}
|
||||
|
||||
public function getShippableOffers () {
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
<?php
|
||||
|
||||
trait Locatable {
|
||||
|
||||
private $lat = null;
|
||||
|
||||
private $lon = null;
|
||||
|
||||
public function getLat () {
|
||||
|
||||
return $this->lat;
|
||||
}
|
||||
|
||||
public function getLon () {
|
||||
|
||||
return $this->lon;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
trait Avatarable {
|
||||
|
||||
private $avatarImgSrc = null;
|
||||
|
||||
public function getAvatarImgSrc () {
|
||||
|
||||
return $this->avatarImgSrc;
|
||||
}
|
||||
}
|
|
@ -2,6 +2,8 @@
|
|||
|
||||
class GchangeRecord {
|
||||
|
||||
use Locatable, Avatarable;
|
||||
|
||||
private $gchangeId;
|
||||
|
||||
private $title;
|
||||
|
@ -10,8 +12,6 @@ class GchangeRecord {
|
|||
|
||||
private $type;
|
||||
|
||||
private $imgSrc = null;
|
||||
|
||||
|
||||
public function __construct ($gchangeObject) {
|
||||
|
||||
|
@ -26,7 +26,7 @@ class GchangeRecord {
|
|||
if (isset($gchangeObject->_source->avatar->_content) and
|
||||
!empty($gchangeObject->_source->avatar->_content)) {
|
||||
|
||||
$this->imgSrc = 'data:'. $gchangeObject->_source->avatar->_content_type .';base64,' . $gchangeObject->_source->avatar->_content;
|
||||
$this->avatarImgSrc = 'data:'. $gchangeObject->_source->avatar->_content_type .';base64,' . $gchangeObject->_source->avatar->_content;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -52,6 +52,6 @@ class GchangeRecord {
|
|||
|
||||
public function getImgSrc () {
|
||||
|
||||
return $this->imgSrc;
|
||||
return $this->getAvatarImgSrc();
|
||||
}
|
||||
}
|
|
@ -1,20 +1,20 @@
|
|||
<?php
|
||||
|
||||
require_once('Gchange.traits.php');
|
||||
|
||||
class GchangeUser {
|
||||
|
||||
private $userGchangeId;
|
||||
use Locatable, Avatarable;
|
||||
|
||||
private $userName;
|
||||
public $userGchangeId;
|
||||
|
||||
private $lat = null;
|
||||
|
||||
private $lon = null;
|
||||
|
||||
private $avatarImgSrc = null;
|
||||
public $userName;
|
||||
|
||||
|
||||
public function __construct ($gchangeObject) {
|
||||
|
||||
$this->gchangeObject = $gchangeObject;
|
||||
|
||||
$this->userGchangeId = $gchangeObject->_id;
|
||||
|
||||
if (isset($gchangeObject->found) and $gchangeObject->found == false) {
|
||||
|
@ -30,7 +30,7 @@ class GchangeUser {
|
|||
}
|
||||
|
||||
if (isset($gchangeObject->_source->geoPoint->lat, $gchangeObject->_source->geoPoint->lon)) {
|
||||
|
||||
|
||||
$this->lat = $gchangeObject->_source->geoPoint->lat;
|
||||
$this->lon = $gchangeObject->_source->geoPoint->lon;
|
||||
}
|
||||
|
@ -54,18 +54,8 @@ class GchangeUser {
|
|||
return $this->userName;
|
||||
}
|
||||
|
||||
public function getLat () {
|
||||
public function jsonify () {
|
||||
|
||||
return $this->lat;
|
||||
}
|
||||
|
||||
public function getLon () {
|
||||
|
||||
return $this->lon;
|
||||
}
|
||||
|
||||
public function getAvatarImgSrc () {
|
||||
|
||||
return $this->avatarImgSrc;
|
||||
return $this->gchangeObject;
|
||||
}
|
||||
}
|
|
@ -7,6 +7,8 @@ class Jaklis {
|
|||
private $mode;
|
||||
|
||||
private $jaklisPath = __DIR__ . '/../vendors/jaklis/jaklis';
|
||||
|
||||
// private $jaklisPath = 'jaklis'; // if you use Docker
|
||||
|
||||
private $nodes = [
|
||||
|
||||
|
@ -15,12 +17,14 @@ class Jaklis {
|
|||
|
||||
private $msgLimit = 15;
|
||||
|
||||
private $pubsecDir = __DIR__ .'/../cache/pubsec/';
|
||||
|
||||
private $userPubsecPath;
|
||||
|
||||
|
||||
public function __construct ($userPubkey, $mode = 'local') {
|
||||
|
||||
$this->userPubsecPath = __DIR__ .'/../cache/pubsec/'. $userPubkey .'.dunikey';
|
||||
$this->userPubsecPath = $this->pubsecDir . $userPubkey .'.dunikey';
|
||||
|
||||
if ($this->mode != 'local') {
|
||||
|
||||
|
@ -32,11 +36,17 @@ class Jaklis {
|
|||
|
||||
if ($this->mode = 'local') {
|
||||
|
||||
return [
|
||||
try {
|
||||
|
||||
$this->getInboundMessages(),
|
||||
$this->getOutboundMessages()
|
||||
];
|
||||
$msg_in = $this->getInboundMessages();
|
||||
$msg_out = $this->getOutboundMessages();
|
||||
|
||||
} catch (Exception $errMsg) {
|
||||
|
||||
throw new Exception($errMsg);
|
||||
}
|
||||
|
||||
return [$msg_in, $msg_out];
|
||||
|
||||
} else {
|
||||
|
||||
|
@ -57,6 +67,11 @@ class Jaklis {
|
|||
$result_code=null;
|
||||
exec($cmd, $output, $result_code);
|
||||
|
||||
if (empty($output)) {
|
||||
|
||||
throw new Exception('Jaklis marche pô pour les messages entrants.');
|
||||
}
|
||||
|
||||
$json = implode("\n", $output);
|
||||
|
||||
// echo '<p>' . $cmd . '</p>';
|
||||
|
@ -83,6 +98,11 @@ class Jaklis {
|
|||
$result_code=null;
|
||||
exec($cmd, $output, $result_code);
|
||||
|
||||
if (empty($output)) {
|
||||
|
||||
throw new Exception('Jaklis marche pô pour les messages sortants.');
|
||||
}
|
||||
|
||||
$json = implode("\n", $output);
|
||||
|
||||
// echo '<p>' . $cmd . '</p>';
|
||||
|
|
|
@ -2,9 +2,100 @@
|
|||
|
||||
class Keygen {
|
||||
|
||||
private $keygenPath = __DIR__ . '/../vendors/keygen/keygen';
|
||||
|
||||
// private $keygenPath = 'keygen'; // if you use Docker
|
||||
|
||||
private $pubsecDir = __DIR__ .'/../cache/pubsec/';
|
||||
|
||||
private $userPubsecPath;
|
||||
|
||||
public function __construct () {
|
||||
|
||||
}
|
||||
|
||||
public function getG1Pub ($salt, $pepper) {
|
||||
|
||||
$salt = str_replace('"', '\"', $salt);
|
||||
$pepper = str_replace('"', '\"', $pepper);
|
||||
|
||||
$cmd = $this->keygenPath;
|
||||
$cmd .= ' -f pubsec';
|
||||
$cmd .= ' -t duniter';
|
||||
$cmd .= ' "'. $salt .'"';
|
||||
$cmd .= ' -p "'. $pepper .'"';
|
||||
|
||||
$output=null;
|
||||
$result_code=null;
|
||||
exec($cmd, $output, $result_code);
|
||||
|
||||
// die($cmd . '<br />'. print_r($output, true) . '<br />'. print_r($result_code, true));
|
||||
|
||||
if (empty($output) or empty($output[0])) {
|
||||
|
||||
throw new Exception('Keygen me calcule pas (la G1 pub)');
|
||||
}
|
||||
|
||||
return $output[0];
|
||||
}
|
||||
|
||||
public function getIPNSPub ($salt, $pepper) {
|
||||
|
||||
$salt = str_replace('"', '\"', $salt);
|
||||
$pepper = str_replace('"', '\"', $pepper);
|
||||
|
||||
$cmd = $this->keygenPath;
|
||||
$cmd .= ' -t b36mf';
|
||||
$cmd .= ' "'. $salt .'"';
|
||||
$cmd .= ' -p "'. $pepper .'"';
|
||||
|
||||
$output=null;
|
||||
$result_code=null;
|
||||
exec($cmd, $output, $result_code);
|
||||
|
||||
// die($cmd . '<br />'. print_r($output, true) . '<br />'. print_r($result_code, true));
|
||||
|
||||
if (empty($output) or empty($output[0])) {
|
||||
|
||||
throw new Exception('Keygen me calcule pas (la pub IPNS) :<br />' . $cmd . '<br />');
|
||||
}
|
||||
|
||||
return $output[0];
|
||||
}
|
||||
|
||||
public function generatePubsec ($salt, $pepper) {
|
||||
|
||||
$salt = str_replace('"', '\"', $salt);
|
||||
$pepper = str_replace('"', '\"', $pepper);
|
||||
|
||||
$userPubkey = $this->getG1Pub($salt, $pepper);
|
||||
|
||||
if (!file_exists($this->pubsecDir)) {
|
||||
|
||||
mkdir($this->pubsecDir, 0777, true);
|
||||
|
||||
}
|
||||
|
||||
if (!file_exists($this->pubsecDir . $userPubkey . '.dunikey')) {
|
||||
|
||||
$cmd = $this->keygenPath;
|
||||
$cmd .= ' -f pubsec';
|
||||
$cmd .= ' -t duniter';
|
||||
$cmd .= ' "'. $salt .'"';
|
||||
$cmd .= ' -p "'. $pepper .'"';
|
||||
$cmd .= ' -o '. $this->pubsecDir . $userPubkey . '.dunikey';
|
||||
|
||||
$output=null;
|
||||
$result_code=null;
|
||||
exec($cmd, $output, $result_code);
|
||||
|
||||
// die($cmd . '<br />'. print_r($result_code, true));
|
||||
|
||||
if ($result_code != 0) {
|
||||
|
||||
throw new Exception('Keygen me calcule pas (la dunikey)');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,313 @@
|
|||
const nodes = {
|
||||
gchange: [
|
||||
'https://data.gchange.fr'
|
||||
]
|
||||
}
|
||||
|
||||
let gameId = 'spationaute'
|
||||
|
||||
async function fetchShippable (n) {
|
||||
|
||||
// var uri = '/market/record/_search?size='+ n +'&_source=title,description&q=description:envoi+possible%20type=offer'
|
||||
|
||||
var uri = '/market/record/_search'
|
||||
|
||||
var query = {
|
||||
size: n
|
||||
, _source: [
|
||||
'title'
|
||||
, 'description'
|
||||
, 'id'
|
||||
, 'picturesCount'
|
||||
, 'pictures'
|
||||
]
|
||||
, query: {
|
||||
bool: {
|
||||
must: [
|
||||
{
|
||||
match: {
|
||||
'description': {
|
||||
|
||||
query: 'envoi possible',
|
||||
operator: 'and'
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
, must_not : [
|
||||
{term : {stock: 0} }
|
||||
]
|
||||
, filter: [
|
||||
{term: {type: 'offer'}}
|
||||
]
|
||||
}
|
||||
}
|
||||
, sort: [
|
||||
{ 'time': 'desc'}
|
||||
]
|
||||
}
|
||||
|
||||
var fetchOpts = {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Accept': 'application/json'
|
||||
},
|
||||
body: JSON.stringify(query)
|
||||
}
|
||||
|
||||
const r = await fetch(nodes['gchange'][0] + uri, fetchOpts)
|
||||
|
||||
if (r.ok === true) {
|
||||
|
||||
return r.json()
|
||||
}
|
||||
|
||||
throw new Error(r.status)
|
||||
|
||||
}
|
||||
|
||||
|
||||
async function fetchImmaterial (n) {
|
||||
|
||||
// var uri = '/market/record/_search?size='+ n +'&_source=title,description&q=description:envoi+possible%20type=offer'
|
||||
|
||||
var uri = '/market/record/_search'
|
||||
|
||||
var query = {
|
||||
size: n
|
||||
, _source: [
|
||||
'title'
|
||||
, 'description'
|
||||
, 'id'
|
||||
, 'picturesCount'
|
||||
, 'pictures'
|
||||
]
|
||||
, query: {
|
||||
nested: {
|
||||
path: 'category',
|
||||
query: {
|
||||
bool: {
|
||||
should: [
|
||||
{term: {'category.parent': 'cat31'}}
|
||||
, {term: {'category.id': 'cat31'}}
|
||||
, {term: {'category.parent': 'cat74'}}
|
||||
, {term: {'category.id': 'cat74'}}
|
||||
]
|
||||
,
|
||||
must_not: [
|
||||
{term: {'category.id': 'cat65'}}
|
||||
, {term : {stock: 0} }
|
||||
]
|
||||
}
|
||||
}
|
||||
,
|
||||
filter: [
|
||||
{term: {type: 'offer'}}
|
||||
]
|
||||
}
|
||||
}
|
||||
, sort: [
|
||||
{ 'time': 'desc'}
|
||||
]
|
||||
}
|
||||
|
||||
var fetchOpts = {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Accept': 'application/json'
|
||||
},
|
||||
body: JSON.stringify(query)
|
||||
}
|
||||
|
||||
const r = await fetch(nodes['gchange'][0] + uri, fetchOpts)
|
||||
|
||||
if (r.ok === true) {
|
||||
|
||||
var obj = r.json()
|
||||
// storeAtFreds(obj)
|
||||
return obj
|
||||
}
|
||||
|
||||
throw new Error(r.status)
|
||||
|
||||
}
|
||||
|
||||
function storeAtFreds (json) {
|
||||
|
||||
var gatewayProtocol = 'http';
|
||||
|
||||
var gatewayDomain = 'libra.copylaradio.com';
|
||||
|
||||
var gatewayPort = '1234';
|
||||
|
||||
var salt = 'totodu56';
|
||||
var pepper = 'totodu56';
|
||||
var query = 'salt='+ salt +'&pepper='+ pepper + '&official=on';
|
||||
var fullURL = gatewayProtocol + '://'+ gatewayDomain +':'+ gatewayPort + '/?' + query;
|
||||
console.log(fullURL)
|
||||
|
||||
const controller = new AbortController()
|
||||
const timeoutId = setTimeout( () => {
|
||||
controller.abort()
|
||||
}, 15000)
|
||||
var fetchOpts = {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'Accept': 'text/html'
|
||||
// ,'Content-Type': 'text/html'
|
||||
// // ,'Access-Control-Allow-Origin': '*',
|
||||
// ,'Origin': 'la-bureautique'
|
||||
// ,'Referrer-Policy': 'unsafe-url'
|
||||
// ,'Redirect': 'manual'
|
||||
},
|
||||
signal: controller.signal
|
||||
}
|
||||
|
||||
fetch(fullURL, fetchOpts)
|
||||
.then(reponse => {
|
||||
return reponse.text()
|
||||
})
|
||||
.then(html => {
|
||||
// console.log(html)
|
||||
|
||||
var regex = /url='([^']+)/i;
|
||||
var redirectURL = html.match(regex)[1]
|
||||
|
||||
return redirectURL
|
||||
})
|
||||
.then(url => {
|
||||
|
||||
console.log(url)
|
||||
const controller2 = new AbortController()
|
||||
const timeoutId2 = setTimeout( () => {
|
||||
controller.abort()
|
||||
}, 15000)
|
||||
var fetchOpts2 = {
|
||||
method: 'GET',
|
||||
|
||||
headers: {
|
||||
'Accept': 'text/html'
|
||||
,'Content-Type': 'text/html'
|
||||
// ,'Access-Control-Allow-Origin': '*',
|
||||
,'Origin': 'la-bureautique'
|
||||
,'Referrer-Policy': 'unsafe-url'
|
||||
,'Redirect': 'manual'
|
||||
},
|
||||
|
||||
mode: 'cors',
|
||||
redirect: 'manual',
|
||||
signal: controller2.signal
|
||||
}
|
||||
fetch(url, fetchOpts2)
|
||||
.then(html => {
|
||||
|
||||
console.log(html)
|
||||
/*
|
||||
var regex = /url='.*\/ipns\/([^']+)/isU;
|
||||
var ipnsKey = html.match(regex)[1]
|
||||
|
||||
return ipnsKey
|
||||
*/
|
||||
}).catch(err => {
|
||||
console.error(err)
|
||||
})
|
||||
})
|
||||
|
||||
// JSON.stringify(json)
|
||||
}
|
||||
|
||||
function displayShippable (records) {
|
||||
|
||||
let offersElt = document.getElementById('shippable-offers');
|
||||
|
||||
for (record of records) {
|
||||
|
||||
offerLi = document.createElement('li')
|
||||
|
||||
offerLink = document.createElement('a')
|
||||
|
||||
offerSpan = document.createElement('span')
|
||||
|
||||
offerImg = document.createElement('img')
|
||||
|
||||
if (record._source.picturesCount > 0) {
|
||||
|
||||
offerImg.src = 'data:' + (record._source.pictures[0].file._content_type) + ';base64,' + (record._source.pictures[0].file._content)
|
||||
|
||||
} else {
|
||||
|
||||
offerImg.src = 'themes/' + gameId + '/default-shippable.256.png'
|
||||
}
|
||||
|
||||
offerImg.alt = record._source.title
|
||||
offerImg.title = record._source.title
|
||||
|
||||
// offerLink.innerHTML = record._source.title
|
||||
offerLink.href = 'https://www.gchange.fr/#/app/market/view/' + record._id + '/'
|
||||
|
||||
offerSpan.append(offerImg)
|
||||
offerLink.append(offerSpan)
|
||||
offerLi.append(offerLink)
|
||||
offersElt.append(offerLi)
|
||||
}
|
||||
}
|
||||
|
||||
function displayImmaterial (records) {
|
||||
|
||||
let offersElt = document.getElementById('immaterial-offers');
|
||||
|
||||
for (record of records) {
|
||||
|
||||
offerLi = document.createElement('li')
|
||||
|
||||
offerLink = document.createElement('a')
|
||||
|
||||
offerSpan = document.createElement('span')
|
||||
|
||||
offerImg = document.createElement('img')
|
||||
|
||||
if (record._source.picturesCount > 0) {
|
||||
|
||||
offerImg.src = 'data:' + (record._source.pictures[0].file._content_type) + ';base64,' + (record._source.pictures[0].file._content)
|
||||
|
||||
} else {
|
||||
|
||||
offerImg.src = 'themes/' + gameId + '/default-immaterial.256.png'
|
||||
}
|
||||
|
||||
offerImg.alt = record._source.title
|
||||
offerImg.title = record._source.title
|
||||
|
||||
// offerLink.innerHTML = record._source.title
|
||||
offerLink.href = 'https://www.gchange.fr/#/app/market/view/' + record._id + '/'
|
||||
|
||||
offerSpan.append(offerImg)
|
||||
offerLink.append(offerSpan)
|
||||
offerLi.append(offerLink)
|
||||
offersElt.append(offerLi)
|
||||
}
|
||||
}
|
||||
|
||||
fetchImmaterial(18)
|
||||
.then(records => {
|
||||
|
||||
displayImmaterial(records.hits.hits)
|
||||
})
|
||||
.catch(error => {
|
||||
if (error == 'Error: 400')
|
||||
console.error('Mauvaise requête')
|
||||
else
|
||||
console.error(error)
|
||||
})
|
||||
|
||||
fetchShippable(18)
|
||||
.then(records => {
|
||||
|
||||
displayShippable(records.hits.hits)
|
||||
})
|
||||
.catch(error => {
|
||||
if (error == 'Error: 400')
|
||||
console.error('Mauvaise requête')
|
||||
else
|
||||
console.error(error)
|
||||
})
|
36
login.php
|
@ -3,25 +3,39 @@ require_once('config.php');
|
|||
require_once('lib/Gchange.class.php');
|
||||
require_once('lib/Fred.class.php');
|
||||
require_once('lib/Keygen.class.php');
|
||||
require_once('lib/ErrorsHandler.class.php');
|
||||
|
||||
|
||||
$toto = 'QP1VkfaFUMdHZmHgPMi7q5wJJHaQhZcEqs5A86NigKr';
|
||||
$boris = '25zB1gSC7Qhwnx463cuDLDCKLRVieLAgFiPbYq6jVHG9';
|
||||
$playerG1Id = null;
|
||||
|
||||
if (isset($_POST['salt'], $_POST['pepper'])) {
|
||||
|
||||
$fred = new Fred();
|
||||
$keygen = new Keygen();
|
||||
$playerG1Id = $fred->donneMoiSaPutaindeG1Pub($_POST['salt'], $_POST['pepper']);
|
||||
try {
|
||||
|
||||
$_SESSION['player_pubkey'] = $playerG1Id;
|
||||
|
||||
$gchange = new Gchange();
|
||||
$user = $gchange->getUser($_SESSION['player_pubkey']);
|
||||
$keygen = new Keygen();
|
||||
|
||||
$_SESSION['player_lat'] = $user->_source->geoPoint->lat;
|
||||
$_SESSION['player_lon'] = $user->_source->geoPoint->lon;
|
||||
$_SESSION['radius'] = DEFAULT_RADIUS;
|
||||
$playerG1Id = $keygen->getG1Pub($_POST['salt'], $_POST['pepper']);
|
||||
$keygen->generatePubsec($_POST['salt'], $_POST['pepper']);
|
||||
|
||||
} catch (Exception $errMsg) {
|
||||
|
||||
try {
|
||||
|
||||
$fred = new Fred();
|
||||
|
||||
$playerG1Id = $fred->donneMoiSaPutainDeG1Pub($_POST['salt'], $_POST['pepper']);
|
||||
|
||||
} catch (Exception $errMsg) {
|
||||
|
||||
ErrorsHandler::kaput($errMsg);
|
||||
}
|
||||
}
|
||||
|
||||
$_SESSION['salt'] = $_POST['salt'];
|
||||
$_SESSION['pepper'] = $_POST['pepper'];
|
||||
$_SESSION['player_pubkey'] = $playerG1Id;
|
||||
|
||||
header('Location:home.php');
|
||||
|
||||
|
@ -62,4 +76,4 @@ if (isset($_POST['salt'], $_POST['pepper'])) {
|
|||
|
||||
include_once('footer.php');
|
||||
|
||||
}
|
||||
}
|
||||
|
|
108
map.php
|
@ -3,6 +3,7 @@
|
|||
require_once('config.php');
|
||||
require_once('lib/Gchange.class.php');
|
||||
require_once('lib/Location.class.php');
|
||||
require_once('lib/ErrorsHandler.class.php');
|
||||
|
||||
if (!isset($_SESSION['player_pubkey'])) {
|
||||
|
||||
|
@ -11,16 +12,27 @@ if (!isset($_SESSION['player_pubkey'])) {
|
|||
|
||||
if (isset($_GET['r']) and in_array($_GET['r'], $radiuses)) {
|
||||
|
||||
$_SESSION['radius'] = $_GET['r'];
|
||||
$_SESSION['searchRadius'] = $_GET['r'];
|
||||
|
||||
} else if (!isset($_SESSION['searchRadius'])) {
|
||||
|
||||
$_SESSION['searchRadius'] = DEFAULT_SEARCH_RADIUS;
|
||||
}
|
||||
|
||||
function getThemeScriptsFullPath ($themeScript) {
|
||||
|
||||
return GAME_JS_DIR . '/' . $themeScript;
|
||||
}
|
||||
|
||||
$gameScripts = array_map('getThemeScriptsFullPath', array_slice(scandir(GAME_JS_DIR), 2));
|
||||
|
||||
|
||||
$javascripts['footer'] = array_merge($javascripts['footer'], $gameScripts);
|
||||
$bodyIds = 'sonar';
|
||||
include_once('header.php');
|
||||
|
||||
|
||||
$gchange = new Gchange();
|
||||
|
||||
|
||||
$player = $gchange->getUser($_SESSION['player_pubkey']);
|
||||
|
||||
// die('<pre>' . print_r($player, true) . '</pre>');
|
||||
|
@ -37,7 +49,7 @@ echo '
|
|||
<nav id="go-back-home">
|
||||
<a href="home.php">
|
||||
<span>
|
||||
'. dgettext($_SESSION['gameId'], _('Retour au tableau de bord')) . '
|
||||
Retour au tableau de bord
|
||||
</span>
|
||||
</a>
|
||||
</nav>
|
||||
|
@ -70,7 +82,7 @@ echo '
|
|||
id="map"
|
||||
data-orig-lat="'. $origLat .'"
|
||||
data-orig-lon="'. $origLon .'"
|
||||
data-radius="'. $_SESSION['radius'] .'"
|
||||
data-radius="'. $_SESSION['searchRadius'] .'"
|
||||
>
|
||||
<div id="map-deco"></div>
|
||||
';
|
||||
|
@ -92,8 +104,8 @@ echo '
|
|||
';
|
||||
*/
|
||||
|
||||
$places = $gchange->getPlacesNearUser($player, $_SESSION['radius']);
|
||||
|
||||
$places = $gchange->getPlacesNearUser($player, $_SESSION['searchRadius'], MAX_NEARBY_PLACES);
|
||||
|
||||
$selectedPlace = NULL;
|
||||
|
||||
foreach ($places as $place) {
|
||||
|
@ -205,43 +217,73 @@ if (isset($selectedPlace)) {
|
|||
|
||||
';
|
||||
|
||||
$visitors = $gchange->getUsersInDaPlace($place->_id);
|
||||
|
||||
|
||||
|
||||
$records_visitors = [];
|
||||
$records_placeCreator = [];
|
||||
|
||||
if (!empty($visitors)) {
|
||||
try {
|
||||
|
||||
echo '
|
||||
<h4>Visiteurs</h4>
|
||||
|
||||
<ul class="visitors">';
|
||||
$records_placeCreator = $gchange->getRecordsByIssuer($place->_source->issuer);
|
||||
|
||||
foreach ($visitors as $visitor) {
|
||||
} catch (Exception $errorMsgs) {
|
||||
|
||||
$records_visitors = array_merge($records_visitors, $gchange->getRecordsByIssuer($visitor->getUserGchangeId()));
|
||||
|
||||
echo '
|
||||
<li class="visitor">';
|
||||
|
||||
$avatarSrc = $visitor->getAvatarImgSrc();
|
||||
$src = !empty($avatarSrc) ? $avatarSrc : $games[$_SESSION['gameId']]['default_avatar'];
|
||||
|
||||
echo '
|
||||
<img src="'. $src . '"
|
||||
alt="'. $visitor->getUserName() .'"
|
||||
title="'. $visitor->getUserName() .'"
|
||||
width="64"
|
||||
height="64" />
|
||||
</li>';
|
||||
}
|
||||
echo '
|
||||
</ul>';
|
||||
// Pas d'annonce pour le créateur du lieu
|
||||
}
|
||||
|
||||
|
||||
$records_placeCreator = $gchange->getRecordsByIssuer($place->_source->issuer);
|
||||
try {
|
||||
|
||||
$visitors = $gchange->getUsersInDaPlace($place->_id);
|
||||
|
||||
if (!empty($visitors)) {
|
||||
|
||||
echo '
|
||||
<h4>Visiteurs</h4>
|
||||
|
||||
<ul class="visitors">';
|
||||
|
||||
foreach ($visitors as $visitor) {
|
||||
|
||||
try {
|
||||
|
||||
$records_visitor = $gchange->getRecordsByIssuer($visitor->getUserGchangeId());
|
||||
$records_visitors = array_merge($records_visitors, $records_visitor);
|
||||
|
||||
echo '
|
||||
<li class="visitor">';
|
||||
|
||||
$avatarSrc = $visitor->getAvatarImgSrc();
|
||||
$src = !empty($avatarSrc) ? $avatarSrc : $games[$_SESSION['gameId']]['default_avatar'];
|
||||
|
||||
echo '
|
||||
<img src="'. $src . '"
|
||||
alt="'. $visitor->getUserName() .'"
|
||||
title="'. $visitor->getUserName() .'"
|
||||
width="64"
|
||||
height="64" />
|
||||
</li>';
|
||||
|
||||
} catch (Exception $errorMsgs) {
|
||||
|
||||
// Pas d'annonce pour cet utilisateur
|
||||
}
|
||||
}
|
||||
echo '
|
||||
</ul>';
|
||||
}
|
||||
|
||||
} catch (Exception $errorMsgs) {
|
||||
|
||||
// Visiteurs trouvés nulle part
|
||||
}
|
||||
|
||||
$records = array_merge($records_placeCreator, $records_visitors);
|
||||
|
||||
|
||||
|
||||
|
||||
$offers = [];
|
||||
$needs = [];
|
||||
$crowdfundings = [];
|
||||
|
|
|
@ -5,6 +5,9 @@ require_once('lib/Fred.class.php');
|
|||
require_once('lib/Messenger.class.php');
|
||||
require_once('lib/Gchange.class.php');
|
||||
require_once('lib/Jaklis.class.php');
|
||||
require_once('lib/ErrorsHandler.class.php');
|
||||
|
||||
$javascripts['header'][] = 'lib/js/messenger.js';
|
||||
|
||||
$gchange = new Gchange();
|
||||
$messenger = new Messenger($gchange);
|
||||
|
@ -24,7 +27,15 @@ if (isset($_POST['message'], $_POST['to'])) {
|
|||
}
|
||||
|
||||
// $msgIn = $jaklis->getInboundMessages('QP1VkfaFUMdHZmHgPMi7q5wJJHaQhZcEqs5A86NigKr');
|
||||
list($msgIn, $msgOut) = $jaklis->getMessages();
|
||||
try {
|
||||
|
||||
list($msgIn, $msgOut) = $jaklis->getMessages();
|
||||
|
||||
} catch (Exception $errMsg) {
|
||||
|
||||
ErrorsHandler::kaput($errMsg);
|
||||
}
|
||||
|
||||
// list($msgIn, $msgOut) = $fred->donneMoiSesPutainDeMessagesGchange($_SESSION['salt'], $_SESSION['pepper']);
|
||||
|
||||
// echo '<pre>'; var_dump($msgIn); echo '</pre>';
|
||||
|
@ -137,14 +148,16 @@ if (isset($_GET['penpal'])) {
|
|||
|
||||
echo '
|
||||
<form method="post" action="">
|
||||
<label for="message">'. _('Message') .'</label>
|
||||
<label for="message">'. 'Message' .'</label>
|
||||
<textarea name="message" rows="1" cols="30"></textarea>
|
||||
|
||||
<input type="hidden" name="to" value="'. htmlspecialchars($_GET['penpal']) .'" />
|
||||
|
||||
<input type="hidden" name="title" value="'. htmlspecialchars($displayedConv->getConvTitle()) .'" />
|
||||
|
||||
<input type="submit" value="'. _('Envoyer') .'" />
|
||||
<p class="submit-button-wrapper">
|
||||
<input type="submit" value="'. 'Envoyer' .'" />
|
||||
</p>
|
||||
</form>
|
||||
';
|
||||
}
|
||||
|
|
|
@ -0,0 +1,393 @@
|
|||
|
||||
async function getCrafts() {
|
||||
|
||||
const res = await fetch("./data/crafts.json");
|
||||
const data = await res.json();
|
||||
|
||||
return data;
|
||||
};
|
||||
|
||||
async function getCollections() {
|
||||
|
||||
const res = await fetch("./data/collections.json");
|
||||
const data = await res.json();
|
||||
|
||||
return data;
|
||||
};
|
||||
|
||||
function updateSelectedCollection (selected = 0) {
|
||||
|
||||
var previouslySelectedCollection = document.querySelector('#collections nav ul li.selected');
|
||||
|
||||
if (previouslySelectedCollection != null) {
|
||||
|
||||
previouslySelectedCollection.classList.remove('selected');
|
||||
}
|
||||
|
||||
|
||||
var collections = document.querySelectorAll('#collections nav ul li');
|
||||
|
||||
console.log(collections);
|
||||
|
||||
var newlySelectedCollection = collections[selected];
|
||||
|
||||
console.log(newlySelectedCollection);
|
||||
|
||||
newlySelectedCollection.classList.add('selected');
|
||||
|
||||
}
|
||||
|
||||
async function printCollections (crafts, collections) {
|
||||
|
||||
var collectionsElt = document.getElementById('collections');
|
||||
var collectionsNavElt = collectionsElt.querySelector('nav ul');
|
||||
|
||||
collectionsNavElt.innerHTML = '';
|
||||
|
||||
var cssClass = '';
|
||||
|
||||
collections.forEach(function (collection, index) {
|
||||
|
||||
if (collection.items != undefined) {
|
||||
|
||||
cssClass = '';
|
||||
|
||||
collectionsNavElt.innerHTML +=
|
||||
'<li' + cssClass + '>' +
|
||||
'<a href="#" ' +
|
||||
'title="' + collection.name + '" ' +
|
||||
'>' +
|
||||
|
||||
'<img src="data/img/' + collection.img + '" ' +
|
||||
'alt="' + collection.name + '" ' +
|
||||
'/>' +
|
||||
'</a>' +
|
||||
'</li>';
|
||||
}
|
||||
});
|
||||
|
||||
displayCollection(crafts, collections);
|
||||
|
||||
collectionsElt.querySelectorAll('li').forEach(function (elt, index) {
|
||||
|
||||
elt.addEventListener('click', function () {
|
||||
|
||||
console.log(index);
|
||||
|
||||
displayCollection(crafts, collections, index);
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
async function displayCollection (crafts, collections, collectionId = 0) {
|
||||
|
||||
updateSelectedCollection(collectionId);
|
||||
|
||||
itemsListElt = document.querySelector('#collections .items-list');
|
||||
|
||||
itemsListElt.innerHTML = '';
|
||||
|
||||
collections[collectionId].items.forEach(function (itemId){
|
||||
|
||||
itemsListElt.innerHTML +=
|
||||
'<li>' +
|
||||
'<a href="#" ' +
|
||||
'onclick="displayRecipe('+ itemId + ', 0)" ' +
|
||||
'title="' + crafts[itemId].name + '" ' +
|
||||
'>' +
|
||||
|
||||
'<img src="data/img/' + crafts[itemId].img + '" ' +
|
||||
'alt="' + crafts[itemId].name + '" ' +
|
||||
'/>' +
|
||||
'</a>' +
|
||||
'</li>';
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
async function printItemsList () {
|
||||
|
||||
crafts = await getCrafts();
|
||||
|
||||
itemsListElt = document.getElementById('items-list');
|
||||
|
||||
crafts.forEach(function (item, index) {
|
||||
|
||||
if (item.recipes != undefined) {
|
||||
|
||||
itemsListElt.innerHTML +=
|
||||
'<li>' +
|
||||
'<a href="#" ' +
|
||||
'onclick="displayRecipe('+ index + ', 0)" ' +
|
||||
'title="' + item.name + '" ' +
|
||||
'>' +
|
||||
|
||||
'<img src="data/img/' + item.img + '" ' +
|
||||
'alt="' + item.name + '" ' +
|
||||
'/>' +
|
||||
'</a>' +
|
||||
'</li>';
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
function padIngredient (nbIngredients, str) {
|
||||
|
||||
if (nbIngredients <= 1 ||
|
||||
nbIngredients == 4 ||
|
||||
nbIngredients == 9 ||
|
||||
nbIngredients == 16) {
|
||||
|
||||
return '';
|
||||
|
||||
} else if (nbIngredients < 4) {
|
||||
|
||||
return str.repeat(4 - nbIngredients);
|
||||
|
||||
} else if (nbIngredients < 9) {
|
||||
|
||||
return str.repeat(9 - nbIngredients);
|
||||
|
||||
} else if (nbIngredients < 16) {
|
||||
|
||||
return str.repeat(16 - nbIngredients);
|
||||
|
||||
} else if (nbIngredients < 25) {
|
||||
|
||||
return str.repeat(25 - nbIngredients);
|
||||
}
|
||||
}
|
||||
|
||||
async function displayRecipe (itemId, recipeId = 0, elementId = 'recipe-main', bc_item = null, bc_recipe = null) {
|
||||
|
||||
crafts = await getCrafts();
|
||||
|
||||
recipeElt = document.getElementById(elementId);
|
||||
ingredientsElt = recipeElt.querySelector('.ingredients');
|
||||
actionElt = recipeElt.querySelector('.action');
|
||||
resultElt = recipeElt.querySelector('.result');
|
||||
itemNameElt = recipeElt.querySelector('.item-name');
|
||||
otherRecipesElt = recipeElt.querySelector('.other-recipes ul');
|
||||
detailsElt = recipeElt.querySelector('.recipe-details');
|
||||
detailsContentElt = detailsElt.querySelector('div');
|
||||
|
||||
actionElt.innerHTML = '<a href="#"> </a>';
|
||||
resultElt.innerHTML = " ";
|
||||
otherRecipesElt.innerHTML = "";
|
||||
detailsContentElt.innerHTML = "";
|
||||
|
||||
recipeElt.style.visibility = 'visible';
|
||||
detailsElt.style.visibility = 'hidden';
|
||||
|
||||
itemNameElt.innerHTML = '' + crafts[itemId].name + '';
|
||||
|
||||
resultElt_content =
|
||||
'<img src="data/img/' + crafts[itemId].img + '" ' +
|
||||
'alt="' + crafts[itemId].name + '" ' +
|
||||
'title="' + crafts[itemId].name + '" ' +
|
||||
'/>';
|
||||
|
||||
if (elementId == 'recipe-aux' && bc_item != null) {
|
||||
|
||||
resultElt_content =
|
||||
'<a href="#" ' +
|
||||
'onclick="displayRecipe(' + bc_item + ', ' + bc_recipe +', \'recipe-aux\')" ' +
|
||||
'>' +
|
||||
resultElt_content +
|
||||
'</a>';
|
||||
}
|
||||
|
||||
resultElt.innerHTML = resultElt_content;
|
||||
|
||||
blackHoleStr = '<li class="ingredient"><img src="data/img/black-hole.png" /></li>';
|
||||
|
||||
|
||||
|
||||
if (crafts[itemId].recipes == undefined) {
|
||||
|
||||
ingredientsElt.innerHTML = blackHoleStr;
|
||||
|
||||
|
||||
} else {
|
||||
|
||||
recipes = crafts[itemId].recipes;
|
||||
|
||||
ingredients = recipes[recipeId].ingredients;
|
||||
|
||||
if (ingredients == undefined) {
|
||||
|
||||
ingredientsElt.innerHTML = blackHoleStr;
|
||||
|
||||
} else {
|
||||
|
||||
ingredientsElt.innerHTML = '';
|
||||
|
||||
nbIngredients = ingredients.length;
|
||||
|
||||
ingredientsElt.className = 'ingredients ';
|
||||
|
||||
if (nbIngredients > 16) {
|
||||
|
||||
ingredientsElt.className += "grid-25";
|
||||
|
||||
} else if (nbIngredients > 9) {
|
||||
|
||||
ingredientsElt.className += "grid-16";
|
||||
|
||||
} else if (nbIngredients > 4) {
|
||||
|
||||
ingredientsElt.className += "grid-9";
|
||||
|
||||
} else if (nbIngredients > 1) {
|
||||
|
||||
ingredientsElt.className += "grid-4";
|
||||
|
||||
} else {
|
||||
|
||||
ingredientsElt.className += "";
|
||||
|
||||
}
|
||||
|
||||
var i = 1;
|
||||
|
||||
console.log(ingredients);
|
||||
|
||||
ingredients.forEach (function (ingredient) {
|
||||
|
||||
unit = (ingredient.unit != undefined) ? (' ' + ingredient.unit) : '';
|
||||
|
||||
qty = (ingredient.qty == undefined) ? '' : '<span class="qty">' + ingredient.qty + '</span>';
|
||||
|
||||
title =
|
||||
(ingredient.qty == undefined) ?
|
||||
crafts[ingredient.ref].name : (
|
||||
(ingredient.unit == undefined) ?
|
||||
ingredient.qty + ' ' + crafts[ingredient.ref].name :
|
||||
ingredient.qty + ' ' + ingredient.unit + ' de ' + crafts[ingredient.ref].name
|
||||
);
|
||||
|
||||
|
||||
// displayOn = (elementId == 'recipe-main') ? 'recipe-aux' : 'recipe-main';
|
||||
displayOn = 'recipe-aux';
|
||||
|
||||
if (elementId == 'recipe-aux') {
|
||||
|
||||
bc_item = itemId;
|
||||
bc_recipe = recipeId;
|
||||
|
||||
} else {
|
||||
|
||||
bc_item = null;
|
||||
bc_recipe = null;
|
||||
}
|
||||
|
||||
ingredientsElt.innerHTML +=
|
||||
'<li class="ingredient">' +
|
||||
qty +
|
||||
'<a href="#" ' +
|
||||
'onclick="displayRecipe('+ ingredient.ref + ', 0, \'' + displayOn + '\', '+ bc_item +', '+ bc_recipe + ')"' +
|
||||
'title="' + title + '"' +
|
||||
'>' +
|
||||
'<img src="data/img/' + crafts[ingredient.ref].img + '" ' +
|
||||
'alt="' + crafts[ingredient.ref].name + '" ' +
|
||||
'/>' +
|
||||
'</a>' +
|
||||
'</li>';
|
||||
|
||||
i++;
|
||||
});
|
||||
|
||||
|
||||
ingredientsElt.innerHTML += padIngredient(nbIngredients, '<li class="ingredient"></li>');
|
||||
}
|
||||
|
||||
|
||||
|
||||
action = (recipes[recipeId].action == undefined) ? '' : recipes[recipeId].action;
|
||||
|
||||
if (recipes[recipeId].details != undefined) {
|
||||
|
||||
actionElt.className += ' has-details';
|
||||
}
|
||||
|
||||
actionElt.innerHTML =
|
||||
'<a href="#" ' +
|
||||
'onclick="showDetails(\'' + elementId + '\', \'' + recipeId + '\')" ' +
|
||||
'>'+
|
||||
action +
|
||||
'</a>';
|
||||
|
||||
|
||||
if ((details = crafts[itemId].recipes[recipeId].details) != undefined) {
|
||||
|
||||
detailsContentElt.innerHTML = details;
|
||||
}
|
||||
|
||||
nbRecipes = recipes.length;
|
||||
|
||||
if (nbRecipes == 1) {
|
||||
|
||||
if (recipes[0].name != undefined) {
|
||||
|
||||
otherRecipesElt.innerHTML +=
|
||||
'<li>' +
|
||||
'<strong>' +
|
||||
recipes[0].name +
|
||||
'</strong>' +
|
||||
'</li>';
|
||||
|
||||
}
|
||||
|
||||
} else if (nbRecipes > 1) {
|
||||
|
||||
for (i = 0; i < nbRecipes; i++) {
|
||||
|
||||
otherRecipeName = (recipes[i].name != undefined) ?
|
||||
recipes[i].name :
|
||||
"recette n°" + (i + 1);
|
||||
|
||||
if (i == recipeId) {
|
||||
|
||||
otherRecipesElt.innerHTML +=
|
||||
'<li>' +
|
||||
'<strong>' +
|
||||
otherRecipeName +
|
||||
'</strong>' +
|
||||
'</li>';
|
||||
|
||||
} else {
|
||||
|
||||
otherRecipesElt.innerHTML +=
|
||||
'<li>' +
|
||||
'<a href="#" ' +
|
||||
'onclick="displayRecipe(' + itemId + ', ' + i + ', \''+ elementId + '\')">' +
|
||||
otherRecipeName +
|
||||
'</a>'
|
||||
'</li>';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
showDetails = function (elementId) {
|
||||
|
||||
detailsElt = document.querySelector('#' + elementId + ' .recipe-details');
|
||||
detailsElt.style.visibility = "visible";
|
||||
}
|
||||
|
||||
// printItemsList();
|
||||
|
||||
window.addEventListener('load', async function () {
|
||||
|
||||
const crafts = await getCrafts();
|
||||
|
||||
const collections = await getCollections();
|
||||
|
||||
printCollections(crafts, collections);
|
||||
});
|
|
@ -0,0 +1,93 @@
|
|||
Copyright 2014 The Comic Neue Project Authors (https://github.com/crozynski/comicneue)
|
||||
|
||||
This Font Software is licensed under the SIL Open Font License, Version 1.1.
|
||||
This license is copied below, and is also available with a FAQ at:
|
||||
http://scripts.sil.org/OFL
|
||||
|
||||
|
||||
-----------------------------------------------------------
|
||||
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
|
||||
-----------------------------------------------------------
|
||||
|
||||
PREAMBLE
|
||||
The goals of the Open Font License (OFL) are to stimulate worldwide
|
||||
development of collaborative font projects, to support the font creation
|
||||
efforts of academic and linguistic communities, and to provide a free and
|
||||
open framework in which fonts may be shared and improved in partnership
|
||||
with others.
|
||||
|
||||
The OFL allows the licensed fonts to be used, studied, modified and
|
||||
redistributed freely as long as they are not sold by themselves. The
|
||||
fonts, including any derivative works, can be bundled, embedded,
|
||||
redistributed and/or sold with any software provided that any reserved
|
||||
names are not used by derivative works. The fonts and derivatives,
|
||||
however, cannot be released under any other type of license. The
|
||||
requirement for fonts to remain under this license does not apply
|
||||
to any document created using the fonts or their derivatives.
|
||||
|
||||
DEFINITIONS
|
||||
"Font Software" refers to the set of files released by the Copyright
|
||||
Holder(s) under this license and clearly marked as such. This may
|
||||
include source files, build scripts and documentation.
|
||||
|
||||
"Reserved Font Name" refers to any names specified as such after the
|
||||
copyright statement(s).
|
||||
|
||||
"Original Version" refers to the collection of Font Software components as
|
||||
distributed by the Copyright Holder(s).
|
||||
|
||||
"Modified Version" refers to any derivative made by adding to, deleting,
|
||||
or substituting -- in part or in whole -- any of the components of the
|
||||
Original Version, by changing formats or by porting the Font Software to a
|
||||
new environment.
|
||||
|
||||
"Author" refers to any designer, engineer, programmer, technical
|
||||
writer or other person who contributed to the Font Software.
|
||||
|
||||
PERMISSION & CONDITIONS
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of the Font Software, to use, study, copy, merge, embed, modify,
|
||||
redistribute, and sell modified and unmodified copies of the Font
|
||||
Software, subject to the following conditions:
|
||||
|
||||
1) Neither the Font Software nor any of its individual components,
|
||||
in Original or Modified Versions, may be sold by itself.
|
||||
|
||||
2) Original or Modified Versions of the Font Software may be bundled,
|
||||
redistributed and/or sold with any software, provided that each copy
|
||||
contains the above copyright notice and this license. These can be
|
||||
included either as stand-alone text files, human-readable headers or
|
||||
in the appropriate machine-readable metadata fields within text or
|
||||
binary files as long as those fields can be easily viewed by the user.
|
||||
|
||||
3) No Modified Version of the Font Software may use the Reserved Font
|
||||
Name(s) unless explicit written permission is granted by the corresponding
|
||||
Copyright Holder. This restriction only applies to the primary font name as
|
||||
presented to the users.
|
||||
|
||||
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
|
||||
Software shall not be used to promote, endorse or advertise any
|
||||
Modified Version, except to acknowledge the contribution(s) of the
|
||||
Copyright Holder(s) and the Author(s) or with their explicit written
|
||||
permission.
|
||||
|
||||
5) The Font Software, modified or unmodified, in part or in whole,
|
||||
must be distributed entirely under this license, and must not be
|
||||
distributed under any other license. The requirement for fonts to
|
||||
remain under this license does not apply to any document created
|
||||
using the Font Software.
|
||||
|
||||
TERMINATION
|
||||
This license becomes null and void if any of the above conditions are
|
||||
not met.
|
||||
|
||||
DISCLAIMER
|
||||
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
||||
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
|
||||
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
||||
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
|
||||
OTHER DEALINGS IN THE FONT SOFTWARE.
|
|
@ -0,0 +1,93 @@
|
|||
Copyright (c) 2010, Kimberly Geswein (kimberlygeswein.com)
|
||||
|
||||
This Font Software is licensed under the SIL Open Font License, Version 1.1.
|
||||
This license is copied below, and is also available with a FAQ at:
|
||||
http://scripts.sil.org/OFL
|
||||
|
||||
|
||||
-----------------------------------------------------------
|
||||
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
|
||||
-----------------------------------------------------------
|
||||
|
||||
PREAMBLE
|
||||
The goals of the Open Font License (OFL) are to stimulate worldwide
|
||||
development of collaborative font projects, to support the font creation
|
||||
efforts of academic and linguistic communities, and to provide a free and
|
||||
open framework in which fonts may be shared and improved in partnership
|
||||
with others.
|
||||
|
||||
The OFL allows the licensed fonts to be used, studied, modified and
|
||||
redistributed freely as long as they are not sold by themselves. The
|
||||
fonts, including any derivative works, can be bundled, embedded,
|
||||
redistributed and/or sold with any software provided that any reserved
|
||||
names are not used by derivative works. The fonts and derivatives,
|
||||
however, cannot be released under any other type of license. The
|
||||
requirement for fonts to remain under this license does not apply
|
||||
to any document created using the fonts or their derivatives.
|
||||
|
||||
DEFINITIONS
|
||||
"Font Software" refers to the set of files released by the Copyright
|
||||
Holder(s) under this license and clearly marked as such. This may
|
||||
include source files, build scripts and documentation.
|
||||
|
||||
"Reserved Font Name" refers to any names specified as such after the
|
||||
copyright statement(s).
|
||||
|
||||
"Original Version" refers to the collection of Font Software components as
|
||||
distributed by the Copyright Holder(s).
|
||||
|
||||
"Modified Version" refers to any derivative made by adding to, deleting,
|
||||
or substituting -- in part or in whole -- any of the components of the
|
||||
Original Version, by changing formats or by porting the Font Software to a
|
||||
new environment.
|
||||
|
||||
"Author" refers to any designer, engineer, programmer, technical
|
||||
writer or other person who contributed to the Font Software.
|
||||
|
||||
PERMISSION & CONDITIONS
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of the Font Software, to use, study, copy, merge, embed, modify,
|
||||
redistribute, and sell modified and unmodified copies of the Font
|
||||
Software, subject to the following conditions:
|
||||
|
||||
1) Neither the Font Software nor any of its individual components,
|
||||
in Original or Modified Versions, may be sold by itself.
|
||||
|
||||
2) Original or Modified Versions of the Font Software may be bundled,
|
||||
redistributed and/or sold with any software, provided that each copy
|
||||
contains the above copyright notice and this license. These can be
|
||||
included either as stand-alone text files, human-readable headers or
|
||||
in the appropriate machine-readable metadata fields within text or
|
||||
binary files as long as those fields can be easily viewed by the user.
|
||||
|
||||
3) No Modified Version of the Font Software may use the Reserved Font
|
||||
Name(s) unless explicit written permission is granted by the corresponding
|
||||
Copyright Holder. This restriction only applies to the primary font name as
|
||||
presented to the users.
|
||||
|
||||
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
|
||||
Software shall not be used to promote, endorse or advertise any
|
||||
Modified Version, except to acknowledge the contribution(s) of the
|
||||
Copyright Holder(s) and the Author(s) or with their explicit written
|
||||
permission.
|
||||
|
||||
5) The Font Software, modified or unmodified, in part or in whole,
|
||||
must be distributed entirely under this license, and must not be
|
||||
distributed under any other license. The requirement for fonts to
|
||||
remain under this license does not apply to any document created
|
||||
using the Font Software.
|
||||
|
||||
TERMINATION
|
||||
This license becomes null and void if any of the above conditions are
|
||||
not met.
|
||||
|
||||
DISCLAIMER
|
||||
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
||||
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
|
||||
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
||||
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
|
||||
OTHER DEALINGS IN THE FONT SOFTWARE.
|
|
@ -0,0 +1,93 @@
|
|||
Copyright (c) 2010-2012 Patrick Wagesreiter (mail@patrickwagesreiter.at)
|
||||
|
||||
This Font Software is licensed under the SIL Open Font License, Version 1.1.
|
||||
This license is copied below, and is also available with a FAQ at:
|
||||
http://scripts.sil.org/OFL
|
||||
|
||||
|
||||
-----------------------------------------------------------
|
||||
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
|
||||
-----------------------------------------------------------
|
||||
|
||||
PREAMBLE
|
||||
The goals of the Open Font License (OFL) are to stimulate worldwide
|
||||
development of collaborative font projects, to support the font creation
|
||||
efforts of academic and linguistic communities, and to provide a free and
|
||||
open framework in which fonts may be shared and improved in partnership
|
||||
with others.
|
||||
|
||||
The OFL allows the licensed fonts to be used, studied, modified and
|
||||
redistributed freely as long as they are not sold by themselves. The
|
||||
fonts, including any derivative works, can be bundled, embedded,
|
||||
redistributed and/or sold with any software provided that any reserved
|
||||
names are not used by derivative works. The fonts and derivatives,
|
||||
however, cannot be released under any other type of license. The
|
||||
requirement for fonts to remain under this license does not apply
|
||||
to any document created using the fonts or their derivatives.
|
||||
|
||||
DEFINITIONS
|
||||
"Font Software" refers to the set of files released by the Copyright
|
||||
Holder(s) under this license and clearly marked as such. This may
|
||||
include source files, build scripts and documentation.
|
||||
|
||||
"Reserved Font Name" refers to any names specified as such after the
|
||||
copyright statement(s).
|
||||
|
||||
"Original Version" refers to the collection of Font Software components as
|
||||
distributed by the Copyright Holder(s).
|
||||
|
||||
"Modified Version" refers to any derivative made by adding to, deleting,
|
||||
or substituting -- in part or in whole -- any of the components of the
|
||||
Original Version, by changing formats or by porting the Font Software to a
|
||||
new environment.
|
||||
|
||||
"Author" refers to any designer, engineer, programmer, technical
|
||||
writer or other person who contributed to the Font Software.
|
||||
|
||||
PERMISSION & CONDITIONS
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of the Font Software, to use, study, copy, merge, embed, modify,
|
||||
redistribute, and sell modified and unmodified copies of the Font
|
||||
Software, subject to the following conditions:
|
||||
|
||||
1) Neither the Font Software nor any of its individual components,
|
||||
in Original or Modified Versions, may be sold by itself.
|
||||
|
||||
2) Original or Modified Versions of the Font Software may be bundled,
|
||||
redistributed and/or sold with any software, provided that each copy
|
||||
contains the above copyright notice and this license. These can be
|
||||
included either as stand-alone text files, human-readable headers or
|
||||
in the appropriate machine-readable metadata fields within text or
|
||||
binary files as long as those fields can be easily viewed by the user.
|
||||
|
||||
3) No Modified Version of the Font Software may use the Reserved Font
|
||||
Name(s) unless explicit written permission is granted by the corresponding
|
||||
Copyright Holder. This restriction only applies to the primary font name as
|
||||
presented to the users.
|
||||
|
||||
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
|
||||
Software shall not be used to promote, endorse or advertise any
|
||||
Modified Version, except to acknowledge the contribution(s) of the
|
||||
Copyright Holder(s) and the Author(s) or with their explicit written
|
||||
permission.
|
||||
|
||||
5) The Font Software, modified or unmodified, in part or in whole,
|
||||
must be distributed entirely under this license, and must not be
|
||||
distributed under any other license. The requirement for fonts to
|
||||
remain under this license does not apply to any document created
|
||||
using the Font Software.
|
||||
|
||||
TERMINATION
|
||||
This license becomes null and void if any of the above conditions are
|
||||
not met.
|
||||
|
||||
DISCLAIMER
|
||||
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
||||
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
|
||||
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
||||
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
|
||||
OTHER DEALINGS IN THE FONT SOFTWARE.
|
|
@ -0,0 +1,499 @@
|
|||
:root {
|
||||
|
||||
--item-size: 32px;
|
||||
|
||||
--marron: hsl(350, 20%, 25%);
|
||||
--marron-medium: hsl(30, 50%, 50%);
|
||||
--marron-clair: hsl(30, 70%, 66%);
|
||||
--marron-transparent: hsla(350, 20%, 25%, 0.80);
|
||||
--blanc: hsl(0, 100%, 100%);
|
||||
--noir: hsl(0, 100%, 0%);
|
||||
--vert-pomme: hsl(100, 70%, 90%);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@font-face {
|
||||
font-family: 'Comic Neue';
|
||||
src: url("../../fonts/Comic_Neue/ComicNeue-Regular.ttf") format('truetype');
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Comic Neue';
|
||||
src: url("../../fonts/Comic_Neue/ComicNeue-Bold.ttf") format('truetype');
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Patrick Hand';
|
||||
src: url("../../fonts/Patrick_Hand/PatrickHand-Regular.ttf") format('truetype');
|
||||
}
|
||||
@font-face {
|
||||
font-family: 'MinecraftFifty';
|
||||
src: url("../../fonts/MinecraftFifty-Solid.otf") format('opentype');
|
||||
}
|
||||
|
||||
body {
|
||||
|
||||
font-family: 'Comic Neue', fantasy;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-family: 'MinecraftFifty', 'Comic Neue', fantasy;
|
||||
}
|
||||
|
||||
#usp {
|
||||
font-family: 'Patrick Hand', fantasy;
|
||||
}
|
||||
|
||||
q:after {
|
||||
|
||||
content: " »";
|
||||
}
|
||||
|
||||
q:before {
|
||||
|
||||
content: "« ";
|
||||
}
|
||||
|
||||
body > footer {
|
||||
|
||||
margin-top: 10rem;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
body > footer blockquote {
|
||||
|
||||
font-family: cursive;
|
||||
font-size: 1.5rem;
|
||||
color: hsl(30, 15%, 90%);
|
||||
}
|
||||
|
||||
body > footer blockquote cite {
|
||||
|
||||
display: block;
|
||||
text-align: right;
|
||||
margin-top: 0.5rem;
|
||||
}
|
||||
|
||||
body > footer blockquote cite:before {
|
||||
|
||||
content: "― ";
|
||||
}
|
||||
|
||||
iframe {
|
||||
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.recipe-name:before {
|
||||
|
||||
content: "« ";
|
||||
}
|
||||
|
||||
.recipe-name:after {
|
||||
|
||||
content: " »";
|
||||
}
|
||||
|
||||
|
||||
main {
|
||||
|
||||
display: flex;
|
||||
width: 100%;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
#recipe-main,
|
||||
#recipe-aux {
|
||||
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 39.999rem) {
|
||||
|
||||
main {
|
||||
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
#recipe-main {
|
||||
|
||||
order: 1;
|
||||
}
|
||||
|
||||
#recipe-aux {
|
||||
|
||||
order: 2;
|
||||
}
|
||||
|
||||
#collections {
|
||||
|
||||
order: 3;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (min-width: 40rem) {
|
||||
|
||||
.recipe {
|
||||
|
||||
width: 48%;
|
||||
padding: 0% 2% 0% 0%;
|
||||
}
|
||||
|
||||
#collections {
|
||||
|
||||
width: 100%;
|
||||
padding: 0% 0% 0% 2%;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (min-width: 60rem) {
|
||||
|
||||
.recipe {
|
||||
|
||||
width: 31.333%;
|
||||
padding: 0% 2% 0% 0%;
|
||||
}
|
||||
|
||||
#collections {
|
||||
|
||||
width: 31.334%;
|
||||
padding: 0% 0% 0% 2%;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
.recipe > .recipe-signature {
|
||||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
|
||||
@keyframes blinking {
|
||||
0% {
|
||||
|
||||
text-shadow: 0 0 0px transparent;
|
||||
}
|
||||
|
||||
50% {
|
||||
|
||||
text-shadow: 0 0 5px var(--vert-pomme),
|
||||
0 0 10px var(--vert-pomme),
|
||||
0 0 15px var(--vert-pomme),
|
||||
0 0 20px var(--vert-pomme),
|
||||
0 0 25px var(--vert-pomme);
|
||||
}
|
||||
|
||||
100% {
|
||||
|
||||
text-shadow: 0 0 0px transparent;
|
||||
}
|
||||
}
|
||||
|
||||
.recipe .action {
|
||||
|
||||
padding: 0 2rem;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.recipe .action a,
|
||||
.recipe .action a:visited {
|
||||
|
||||
text-decoration: none;
|
||||
color: var(--noir);
|
||||
background-color: var(--blanc);
|
||||
transition: text-shadow 0.666s;
|
||||
}
|
||||
|
||||
.recipe .action.has-details a,
|
||||
.recipe .action.has-details a:visited {
|
||||
|
||||
animation: blinking 3s infinite;
|
||||
}
|
||||
|
||||
.recipe .action:hover a,
|
||||
.recipe .action:hover a:before {
|
||||
|
||||
}
|
||||
|
||||
.recipe .action *:before {
|
||||
|
||||
content: "⇒";
|
||||
display: block;
|
||||
font-size: 2rem;
|
||||
font-weight: bolder;
|
||||
}
|
||||
|
||||
.recipe .ingredients {
|
||||
|
||||
list-style-type: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
display: grid;
|
||||
grid-gap: 0;
|
||||
border: 2px solid var(--marron);
|
||||
}
|
||||
|
||||
|
||||
.recipe .ingredients.grid-4 {
|
||||
|
||||
grid-template-columns: 50% 50%;
|
||||
max-width: calc(2 * (var(--item-size) + 24px + 4px * 2));
|
||||
|
||||
}
|
||||
|
||||
.recipe .ingredients.grid-9 {
|
||||
|
||||
grid-template-columns: 33.333% 33.333% 33.333%;
|
||||
max-width: calc(3 * (var(--item-size) + 24px + 4px * 2));
|
||||
|
||||
}
|
||||
|
||||
.recipe .ingredients.grid-16 {
|
||||
|
||||
grid-template-columns: 25% 25% 25% 25%;
|
||||
max-width: calc(4 * (var(--item-size) + 24px + 4px * 2));
|
||||
|
||||
}
|
||||
|
||||
.recipe .ingredients.grid-25 {
|
||||
|
||||
grid-template-columns: 20% 20% 20% 20% 20%;
|
||||
max-width: calc(5 * (var(--item-size) + 24px + 4px * 2));
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
.result {
|
||||
|
||||
border: 4px solid var(--marron);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#items-list,
|
||||
.items-list,
|
||||
#collections nav ul {
|
||||
|
||||
list-style-type: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
#collections nav {
|
||||
|
||||
display: flex;
|
||||
}
|
||||
|
||||
#collections nav ul {
|
||||
|
||||
margin-bottom: 1rem;
|
||||
border: 0.25rem solid var(--marron);
|
||||
border-radius: 1rem;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
#collections nav ul li.selected {
|
||||
|
||||
background-color: var(--marron-clair);
|
||||
}
|
||||
|
||||
/*
|
||||
#collections nav ul li {
|
||||
|
||||
border-left: 0.5rem solid var(--marron);
|
||||
border-right: 0.5rem solid var(--marron);
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
|
||||
#collections nav ul li:first-child {
|
||||
|
||||
border-left: 0;
|
||||
}
|
||||
|
||||
#collections nav ul li:last-child {
|
||||
|
||||
border-right: 0;
|
||||
}
|
||||
*/
|
||||
|
||||
.recipe .ingredients .ingredient,
|
||||
#items-list li,
|
||||
.items-list li {
|
||||
|
||||
border: 2px solid var(--marron);
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
|
||||
#items-list li,
|
||||
.items-list li,
|
||||
#collections nav ul li {
|
||||
|
||||
height: 48px;
|
||||
width: 48px;
|
||||
|
||||
}
|
||||
|
||||
.recipe .ingredients .ingredient a,
|
||||
#items-list li a,
|
||||
.items-list li a,
|
||||
#collections nav ul li a {
|
||||
|
||||
z-index: 10;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.recipe .ingredients .ingredient:hover a,
|
||||
#items-list li:hover a,
|
||||
.items-list li:hover a,
|
||||
#collections nav ul li:hover a {
|
||||
|
||||
background-color: var(--marron-clair);
|
||||
}
|
||||
|
||||
.recipe .ingredients .ingredient:hover a {
|
||||
|
||||
border: 2px solid var(--marron-medium);
|
||||
}
|
||||
|
||||
|
||||
.recipe .ingredients .ingredient,
|
||||
.recipe .result,
|
||||
#items-list li,
|
||||
#collections nav ul li {
|
||||
|
||||
position: relative;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
.recipe .ingredients .ingredient {
|
||||
}
|
||||
|
||||
.recipe .ingredients .ingredient img {
|
||||
|
||||
flex-basis: var(--item-size);
|
||||
flex-grow: 0;
|
||||
}
|
||||
|
||||
.recipe .ingredients .ingredient .qty {
|
||||
|
||||
position: absolute;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
z-index: 100;
|
||||
font-weight: bold;
|
||||
font-size: 1.25rem;
|
||||
background-color: var(--marron-transparent);
|
||||
color: var(--blanc);
|
||||
padding-left: 0.375rem;
|
||||
padding-right: 0.125rem;
|
||||
padding-top: 0.25rem;
|
||||
border-top-left-radius: 0.33em;
|
||||
}
|
||||
|
||||
|
||||
.recipe .ingredients .ingredient,
|
||||
.recipe .result {
|
||||
|
||||
height: 64px;
|
||||
width: 64px;
|
||||
|
||||
}
|
||||
|
||||
.other-recipes ul {
|
||||
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
padding-top: 0px;
|
||||
margin: 0;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.other-recipes ul {
|
||||
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
display: flex;
|
||||
height: 2.5rem;
|
||||
padding-top: 1rem;
|
||||
width: auto;
|
||||
width: auto;
|
||||
overflow-y: hidden;
|
||||
overflow-x: visible;
|
||||
flex-wrap: nowrap;
|
||||
}
|
||||
|
||||
.other-recipes li {
|
||||
|
||||
margin: 0;
|
||||
margin-right: 0.5rem;
|
||||
padding: 0;
|
||||
display: inline;
|
||||
flex-basis: auto;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.other-recipes li > * {
|
||||
|
||||
width: 2rem;
|
||||
text-align: center;
|
||||
height: 2rem;
|
||||
display: inline;
|
||||
|
||||
padding: 0.25rem 0.5em;
|
||||
|
||||
border-radius: 1rem;
|
||||
text-decoration: none;
|
||||
border-width: 2px;
|
||||
border-style: solid;
|
||||
|
||||
|
||||
border-color: var(--marron);
|
||||
background-color: var(--blanc);
|
||||
color: var(--marron);
|
||||
|
||||
}
|
||||
|
||||
.other-recipes li *:not(a) {
|
||||
|
||||
border-color: var(--marron);
|
||||
color: var(--blanc);
|
||||
background-color: var(--marron);
|
||||
|
||||
}
|
||||
|
||||
.recipe-details {
|
||||
|
||||
visibility: hidden;
|
||||
}
|
|
@ -0,0 +1,75 @@
|
|||
[
|
||||
|
||||
{
|
||||
"name": "habitat",
|
||||
"img": "carpenter.png",
|
||||
"items": [
|
||||
4,
|
||||
0,
|
||||
1,
|
||||
12,
|
||||
7,
|
||||
11,
|
||||
13,
|
||||
58
|
||||
]
|
||||
}
|
||||
|
||||
,{
|
||||
"name": "culture",
|
||||
"img": "farmer.png",
|
||||
"items": [
|
||||
28,
|
||||
36,
|
||||
57,
|
||||
56,
|
||||
42,
|
||||
43,
|
||||
3,
|
||||
59,
|
||||
35,
|
||||
49,
|
||||
86
|
||||
]
|
||||
}
|
||||
|
||||
,{
|
||||
"name": "cuisine",
|
||||
"img": "chef.png",
|
||||
"items": [
|
||||
33,
|
||||
17,
|
||||
44,
|
||||
87
|
||||
]
|
||||
}
|
||||
|
||||
,{
|
||||
"name": "vêtement",
|
||||
"img": "sewing.png",
|
||||
"items": [
|
||||
54
|
||||
]
|
||||
}
|
||||
|
||||
,{
|
||||
"name": "soin",
|
||||
"img": "arm-plaster.png",
|
||||
"items": [
|
||||
101,
|
||||
83,
|
||||
67,
|
||||
68,
|
||||
69,
|
||||
70,
|
||||
71,
|
||||
72,
|
||||
73,
|
||||
74,
|
||||
75,
|
||||
77,
|
||||
100
|
||||
|
||||
]
|
||||
}
|
||||
]
|
After Width: | Height: | Size: 1.3 KiB |
After Width: | Height: | Size: 1.8 KiB |
After Width: | Height: | Size: 2.0 KiB |
After Width: | Height: | Size: 1.6 KiB |
After Width: | Height: | Size: 1.3 KiB |
After Width: | Height: | Size: 1.9 KiB |
After Width: | Height: | Size: 5.0 KiB |
After Width: | Height: | Size: 1.5 KiB |
After Width: | Height: | Size: 1.8 KiB |
After Width: | Height: | Size: 1.6 KiB |
After Width: | Height: | Size: 2.0 KiB |
After Width: | Height: | Size: 1.9 KiB |
After Width: | Height: | Size: 675 B |
After Width: | Height: | Size: 15 KiB |
After Width: | Height: | Size: 2.0 KiB |
After Width: | Height: | Size: 1.3 KiB |
After Width: | Height: | Size: 1.4 KiB |
After Width: | Height: | Size: 1.3 KiB |
After Width: | Height: | Size: 1.5 KiB |
After Width: | Height: | Size: 2.5 KiB |
After Width: | Height: | Size: 1.6 KiB |
After Width: | Height: | Size: 965 B |
After Width: | Height: | Size: 2.0 KiB |
After Width: | Height: | Size: 2.0 KiB |
After Width: | Height: | Size: 1.6 KiB |
After Width: | Height: | Size: 1.9 KiB |
After Width: | Height: | Size: 1.4 KiB |
After Width: | Height: | Size: 2.0 KiB |
After Width: | Height: | Size: 1.5 KiB |
After Width: | Height: | Size: 1.8 KiB |
After Width: | Height: | Size: 1.9 KiB |
After Width: | Height: | Size: 1.8 KiB |
After Width: | Height: | Size: 870 B |
After Width: | Height: | Size: 1.5 KiB |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 1.5 KiB |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 1.4 KiB |
After Width: | Height: | Size: 1.8 KiB |
After Width: | Height: | Size: 1.3 KiB |
After Width: | Height: | Size: 1.7 KiB |
After Width: | Height: | Size: 2.1 KiB |
After Width: | Height: | Size: 1.4 KiB |
After Width: | Height: | Size: 1.8 KiB |
After Width: | Height: | Size: 1.4 KiB |
After Width: | Height: | Size: 2.4 KiB |
After Width: | Height: | Size: 1.5 KiB |
After Width: | Height: | Size: 1.4 KiB |
After Width: | Height: | Size: 2.4 KiB |
After Width: | Height: | Size: 1.7 KiB |
After Width: | Height: | Size: 1.6 KiB |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 1.6 KiB |
After Width: | Height: | Size: 1.7 KiB |
After Width: | Height: | Size: 1.9 KiB |