Compare commits

..

5 Commits

Author SHA1 Message Date
25e5ce5a93 versions 2024-03-14 11:39:38 +01:00
83724726b7 initial commit front 2024-03-14 10:29:58 +01:00
26b59425b7 refactor repo 2024-03-14 10:20:30 +01:00
de18726abb reset 2024-03-14 10:16:52 +01:00
027f62ea0d refactor repo 2024-03-14 10:10:45 +01:00
46 changed files with 13619 additions and 1 deletions

View File

@@ -0,0 +1 @@
# Jeu concours

View File

@@ -0,0 +1,22 @@
# syntax=docker/dockerfile:1.4
# la ligne du dessus est la version de syntaxe du format Dockerfile
# Récupère l'image docker python:3.10-alpine sur DockerHub
# AS builder permet de nommer cette image sour la référence "builder" pour la suite du fichier, à la manière d'un alias
FROM --platform=$BUILDPLATFORM python:3.10-alpine AS builder
# définie le répertoire de travail, les commandes suivantes seront jouées à partir de ce répertoire
WORKDIR /app
# on copie requirements.txt et app/ dans l'image
COPY requirements.txt /app
# installe les dépendance python à l'aide de PIP, disponible dans l'image suite au téléchargement de l'image python:3.10-alpine
RUN --mount=type=cache,target=/root/.cache/pip \
pip3 install -r requirements.txt
# Copie l'ensemble des fichiers dans /app,
COPY . /app
# Ces deux lignes permet au lancement de l'image, d'executer python3 avec comme argument app.py
ENTRYPOINT ["python3"]
CMD ["app.py"]

View File

@@ -0,0 +1,52 @@
import logging
from flask import Flask, render_template
from redis import Redis
from pygelf import GelfTcpHandler, GelfUdpHandler, GelfTlsHandler, GelfHttpHandler
import os
app = Flask(__name__)
visitor_count = 0
# CONF
cache_port = os.getenv('CACHE_PORT')
cache_host = os.getenv('CACHE_HOST')
app_port = os.getenv('APP_PORT')
def set_logger():
log_handler = GelfUdpHandler(host='logstash' , port=12201)
app.logger.addHandler(log_handler)
# app.logger.setLevel(logging.INFO)
# GET REDIS
def get_redis_connection():
return Redis(host=cache_host, port=cache_port)
def init_visitor_count(redis_db: Redis):
key = 'visitor_count'
if not redis_db.exists(key):
redis_db.set(key, 0)
# MAIN ROUTE
@app.route('/')
def index():
try:
set_logger()
except Exception as e:
print('Error: logger not available')
try:
redis_db = get_redis_connection()
init_visitor_count(redis_db)
visitor_count = redis_db.incr('visitor_count')
app.logger.info("Visit page")
except Exception as e:
return render_template('erreur.html', message=str(e))
if visitor_count == 10:
return render_template('winner.html')
return render_template('index.html', visitor_count=visitor_count)
if __name__ == '__main__':
app.run(host='0.0.0.0', port=app_port)

View File

@@ -0,0 +1 @@
flask

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 826 KiB

View File

@@ -0,0 +1,71 @@
body {
font-family: Arial, sans-serif;
text-align: center;
padding: 50px;
}
.container {
background-color: #f2f2f2;
padding: 20px;
border-radius: 5px;
}
h1 {
color: #333;
}
p {
color: #666;
}
/* Conteneur de l'image */
.img-container {
width: 100%; /* Largeur complète */
height: 150px; /* Hauteur fixée à 150px */
overflow: hidden; /* Masquer tout ce qui dépasse */
}
.oh-well {
width: auto;
height: 250px;
}
.congratulations {
width: auto;
height: 400px;
}
/* Conteneur de l'image */
.img-container-bottom {
height: 150px;
overflow: hidden;
position: fixed;
left: 0;
bottom: 0;
width: 100%;
}
/* Style pour l'image des jetons */
.img-jetons {
width: 100%; /* Largeur complète */
height: auto; /* Hauteur automatique pour maintenir le ratio */
display: block; /* Assurer que l'image s'affiche correctement */
}
footer {
background-color: #c3c3c3;
text-align: center;
padding: 20px;
position: fixed;
left: 0;
bottom: 0;
width: 100%;
font-size: 0.8em;
opacity: 0.9;
}
footer p {
margin: 0;
line-height: 1.5;
color: #000;
}

View File

@@ -0,0 +1,69 @@
<!DOCTYPE html>
<!-- saved from url=(0087)https://moodle.ynov.com/pluginfile.php/1100513/mod_resource/content/0/winner%20tpl.html -->
<html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Jeu Concours</title>
<link rel="stylesheet" href="../static/style.css">
<link rel="preconnect" href="https://fonts.googleapis.com/"><link rel="preconnect" href="https://fonts.gstatic.com/" crossorigin=""><link rel="stylesheet" href="./Jeu Concours_files/css2" class="wtd-font"><link rel="stylesheet" href="./Jeu Concours_files/css2(1)" class="wtd-font"></head>
<body>
<div class="img-container">
<img src="../static/jetons.png" alt="Jetons de Casino" class="img-jetons">
</div>
<h1>Bienvenue sur notre jeu concours !</h1>
<p class="congrat-text">Vous êtes le 10ème visiteur ! Bravo ! Vous avez gagné votre diplôme !</p>
<img src="../static/congratulations.png" alt="Félicitations" class="congratulations" "="">
<div class="img-container-bottom">
<img src="../static/jetons.png" alt="Jetons de Casino" class="img-jetons">
</div>
<footer>
<p>
Ce jeu concours est fourni à titre de divertissement uniquement. Aucun achat nécessaire.
Toute ressemblance avec des personnes réelles, vivantes ou décédées, ou des événements réels est purement fortuite.
Les conditions et restrictions s'appliquent. Voir les détails complets du jeu pour plus d'informations.
</p>
</footer>
<script id="define-custom-element-wtd-root">
(() => {
window.customElements.whenDefined('wtd-root').then(() => {
window.dispatchEvent(
new CustomEvent('customElements.defined', {
detail: {
name: 'wtd-root',
},
}),
);
});
if (window.customElements.get('wtd-root')) return;
window.customElements.define('wtd-root', class extends HTMLElement {
constructor() {
super();
this.attachShadow({ mode: 'open' });
}
});
})();
</script><wtd-root id="cashback"><template shadowrootmode="open"><div id="root"></div><link rel="stylesheet" href="chrome-extension://emnoomldgleagdjapdeckpmebokijail/tailwind/tailwind.css"></template></wtd-root><script id="define-custom-element-wtd-div">
(() => {
window.customElements.whenDefined('wtd-div').then(() => {
window.dispatchEvent(
new CustomEvent('customElements.defined', {
detail: {
name: 'wtd-div',
},
}),
);
});
if (window.customElements.get('wtd-div')) return;
window.customElements.define('wtd-div', class extends HTMLElement {
constructor() {
super();
}
});
})();
</script><wtd-div id="wanteeedContainer" style="position: fixed; display: block; top: 0px; right: 0px; z-index: 2147483647;"><wtd-root id="comparator"><template shadowrootmode="open"><div id="root"><div class="pointer-events-none z-[2147483647] flex select-none flex-col items-end overflow-hidden font-sans antialiased"></div></div><link rel="stylesheet" href="chrome-extension://emnoomldgleagdjapdeckpmebokijail/tailwind/tailwind.css"></template></wtd-root><iframe id="wanteeedPanel" data-version="1.134.0" allowtransparency="true" style="background-color: rgb(255, 255, 255); border: none; border-radius: 3px; box-shadow: rgb(181, 181, 181) 1px 1px 3px 2px; clip: auto; display: none; margin-left: auto; margin-right: 12px; margin-top: 12px; position: relative; z-index: 2147483647; height: 1px; width: 1px;" src="./Jeu Concours_files/saved_resource.html"></iframe></wtd-div><iframe id="wanteeedTestMaker" data-version="1.134.0" allowtransparency="true" style="border: none; clip: auto; display: none; left: 0px; overflow: hidden; position: fixed; top: 10px; transition: all 0.2s ease-out 0s; z-index: 45739864; height: 1px; width: 1px;" src="./Jeu Concours_files/saved_resource(1).html"></iframe></body></html>

View File

@@ -0,0 +1,27 @@
<!DOCTYPE html>
<html>
<head>
<title>Jeu Concours</title>
<link rel="stylesheet" href="../static/style.css">
</head>
<body>
<div class="img-container">
<img src="../static/jetons.png" alt="Jetons de Casino" class="img-jetons">
</div>
<h1>Bienvenue sur notre jeu concours !</h1>
<p>Vous êtes le {{ visitor_count }}ème visiteur.</p>
<p>Retentez votre chance une autre fois !</p>
<img src="../static/oh_well.png" alt="Désolé" class="oh-well">
<div class="img-container-bottom">
<img src="../static//jetons.png" alt="Jetons de Casino" class="img-jetons">
</div>
<footer>
<p>
Ce jeu concours est fourni à titre de divertissement uniquement. Aucun achat nécessaire.
Toute ressemblance avec des personnes réelles, vivantes ou décédées, ou des événements réels est purement fortuite.
Les conditions et restrictions s'appliquent. Voir les détails complets du jeu pour plus d'informations.
</p>
</footer>
</body>
</html>

View File

@@ -0,0 +1,20 @@
import unittest
from app import app
class FlaskAppTests(unittest.TestCase):
def setUp(self):
# Crée un client de test
self.app = app.test_client()
self.app.testing = True
def test_winner_template_rendered_on_10th_visit(self):
# Test pour vérifier si le template winner.html est rendu après le 10ème visite
for _ in range(9):
self.app.get('/')
response = self.app.get('/')
# Cette assertion dépend de la manière dont vous affichez le contenu dans 'winner.html'
self.assertIn('Vous avez gagné votre diplôme', response.get_data(as_text=True))
if __name__ == '__main__':
unittest.main()

View File

@@ -0,0 +1,18 @@
import unittest
from app import app
class FlaskAppTests(unittest.TestCase):
def setUp(self):
# Crée un client de test
self.app = app.test_client()
self.app.testing = True
def test_index_page(self):
# Test pour s'assurer que l'index se charge correctement
response = self.app.get('/')
self.assertEqual(response.status_code, 200)
if __name__ == '__main__':
unittest.main()

View File

@@ -0,0 +1,28 @@
version: '3.7'
services:
jeu_concours:
image: localhost:3000/pom/jeu-concours:latest
ports:
- "8000:8000"
environment:
CACHE_HOST: "${CACHE_HOST}"
CACHE_PORT: "${CACHE_PORT}"
APP_PORT: "${APP_PORT}"
deploy:
replicas: 3
update_config:
parallelism: 2
delay: 10s
redis:
image: redis:alpine
networks:
- minicloud_network
ports:
- "6379:6379"
deploy:
replicas: 1
networks:
minicloud_network:
external: true

View File

@@ -0,0 +1,7 @@
# Application Flask de citations inspirantes avec sessions et Redis
## Groupe
- Yves-Robert ESTRADA
- Mustapha AIT HAMOU
- Sinclair BALIVET
- Pauline SRIFI

View File

@@ -0,0 +1,23 @@
name: Gitea Actions for feature
run-name: ${{ gitea.actor }} testing jobs
on:
push:
branches:
- features/*
jobs:
Tests-Actions:
runs-on: ubuntu-latest
container: catthehacker/ubuntu:act-latest
steps:
- name: Check out repository code
uses: actions/checkout@v3
with:
github-server-url: 'http://localhost:3000'
- uses: actions/setup-python@v5
- name: Install dependencies
run: |
cd app
pip3 install -r requirements.test.txt
- name: "Testing..."
run: cd app && python3 -m unittest discover -s tests

Submodule backend_part1/rendu_inspirasite/ispirasite added at 488ccfb3cf

View File

@@ -0,0 +1,43 @@
name: Gitea Actions for prod
run-name: ${{ gitea.actor }} deploy prod
on:
push:
tags:
- 'v*'
jobs:
Deploy-Staging-Actions:
runs-on: ubuntu-latest
container: catthehacker/ubuntu:act-latest
steps:
- name: Check out repository code
uses: actions/checkout@v3
with:
github-server-url: http://localhost:3000
- name: Login to the registry
uses: docker/login-action@v2
with:
registry: http://localhost:3000
username: ${{ github.repository_owner }}
password: ${{ secrets.token }}
- name: Build and push
uses: docker/build-push-action@v2
with:
context: ./app
file: ./app/Dockerfile
platforms: linux/amd64
push: true
tags: localhost:3000/${{ gitea.repository }}:latest
- name: Generate stack yml for deployment
uses: nowactions/envsubst@v1
with:
input: ./stack_prod.tpl.yml
output: ./stack_prod.yml
env:
CACHE_HOST: "${{ vars.CACHE_HOST }}"
CACHE_PORT: "${{ vars.CACHE_PORT }}"
APP_PORT: "${{ vars.APP_PORT }}"
SECRET_KEY: "${{ vars.SECRET_KEY }}"
TTL: "${{ vars.TTL }}"
- name: Deploy
run: docker stack deploy -c ./stack_prod.yml inspirasite_prod

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

View File

@@ -0,0 +1,43 @@
name: Gitea Actions for staging
run-name: ${{ gitea.actor }} deploy staging
on:
push:
branches:
- main
jobs:
Deploy-Staging-Actions:
runs-on: ubuntu-latest
container: catthehacker/ubuntu:act-latest
steps:
- name: Check out repository code
uses: actions/checkout@v3
with:
github-server-url: http://localhost:3000
- name: Login to the registry
uses: docker/login-action@v2
with:
registry: http://localhost:3000
username: ${{ github.repository_owner }}
password: ${{ secrets.token }}
- name: Build and push
uses: docker/build-push-action@v2
with:
context: ./app
file: ./app/Dockerfile
platforms: linux/amd64
push: true
tags: localhost:3000/${{ gitea.repository }}:latest
- name: Generate stack yml for deployment
uses: nowactions/envsubst@v1
with:
input: ./stack_staging.tpl.yml
output: ./stack_staging.yml
env:
CACHE_HOST: "${{ vars.CACHE_HOST }}"
CACHE_PORT: "${{ vars.CACHE_PORT_STAGING }}"
APP_PORT: "${{ vars.APP_PORT_STAGING }}"
SECRET_KEY: "${{ vars.SECRET_KEY_STAGING }}"
TTL: "${{ vars.TTL_STAGING }}"
- name: Deploy
run: docker stack deploy -c ./stack_staging.yml inspirasite_staging

Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

View File

@@ -0,0 +1,10 @@
input {
gelf {
}
}
output {
elasticsearch {
hosts => "elasticsearch:9200"
}
}

View File

@@ -0,0 +1,40 @@
version: '3'
services:
elasticsearch:
image: elasticsearch:7.9.3
environment:
- discovery.type=single-node
- ES_JAVA_OPTS=-Xms2g -Xmx2g
networks:
- minicloud_network
volumes:
- esdata:/usr/share/elasticsearch/data
kibana:
image: kibana:7.9.3
depends_on:
- elasticsearch
ports:
- "5601:5601"
networks:
- minicloud_network
logstash:
image: logstash:7.9.3
ports:
- "12201:12201"
depends_on:
- elasticsearch
deploy:
mode: global
networks:
- minicloud_network
volumes:
- ./logstash-pipeline:/usr/share/logstash/pipeline/
volumes:
esdata:
driver: local
logstash-pipeline:
driver: local
networks:
minicloud_network:
external: true

3
frontend_part2/readme.MD Normal file
View File

@@ -0,0 +1,3 @@
# Front end part
Application react native

View File

@@ -0,0 +1,35 @@
# Learn more https://docs.github.com/en/get-started/getting-started-with-git/ignoring-files
# dependencies
node_modules/
# Expo
.expo/
dist/
web-build/
# Native
*.orig.*
*.jks
*.p8
*.p12
*.key
*.mobileprovision
# Metro
.metro-health-check*
# debug
npm-debug.*
yarn-debug.*
yarn-error.*
# macOS
.DS_Store
*.pem
# local env files
.env*.local
# typescript
*.tsbuildinfo

5
frontend_part2/web-cloud-ynov/.idea/.gitignore generated vendored Normal file
View File

@@ -0,0 +1,5 @@
# Default ignored files
/shelf/
/workspace.xml
# Editor-based HTTP Client requests
/httpRequests/

View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/web-cloud-ynov.iml" filepath="$PROJECT_DIR$/.idea/web-cloud-ynov.iml" />
</modules>
</component>
</project>

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$/../.." vcs="Git" />
</component>
</project>

View File

@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="WEB_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$">
<excludeFolder url="file://$MODULE_DIR$/.tmp" />
<excludeFolder url="file://$MODULE_DIR$/temp" />
<excludeFolder url="file://$MODULE_DIR$/tmp" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

View File

@@ -0,0 +1,20 @@
import { StatusBar } from 'expo-status-bar';
import { StyleSheet, Text, View } from 'react-native';
export default function App() {
return (
<View style={styles.container}>
<Text>Open up App.js to start working on your app!</Text>
<StatusBar style="auto" />
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
},
});

View File

@@ -0,0 +1,30 @@
{
"expo": {
"name": "web-cloud-ynov",
"slug": "web-cloud-ynov",
"version": "1.0.0",
"orientation": "portrait",
"icon": "./assets/icon.png",
"userInterfaceStyle": "light",
"splash": {
"image": "./assets/splash.png",
"resizeMode": "contain",
"backgroundColor": "#ffffff"
},
"assetBundlePatterns": [
"**/*"
],
"ios": {
"supportsTablet": true
},
"android": {
"adaptiveIcon": {
"foregroundImage": "./assets/adaptive-icon.png",
"backgroundColor": "#ffffff"
}
},
"web": {
"favicon": "./assets/favicon.png"
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

View File

@@ -0,0 +1,6 @@
module.exports = function(api) {
api.cache(true);
return {
presets: ['babel-preset-expo'],
};
};

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,24 @@
{
"name": "web-cloud-ynov",
"version": "1.0.0",
"main": "node_modules/expo/AppEntry.js",
"scripts": {
"start": "expo start",
"android": "expo start --android",
"ios": "expo start --ios",
"web": "expo start --web"
},
"dependencies": {
"expo": "~50.0.13",
"expo-status-bar": "~1.11.1",
"react": "18.2.0",
"react-native": "0.73.5",
"react-dom": "18.2.0",
"react-native-web": "~0.19.6",
"@expo/metro-runtime": "~3.1.3"
},
"devDependencies": {
"@babel/core": "^7.20.0"
},
"private": true
}

Submodule jeu-concours deleted from 7ad6dc5630