first commit
commit
d6fa621e8e
@ -0,0 +1,2 @@
|
||||
venv
|
||||
__pycache__
|
@ -0,0 +1,12 @@
|
||||
# Projet API
|
||||
|
||||
### Description
|
||||
|
||||
Ce projet a été réaliser dans le cadre du cours de python en formation DEVOPS au CNAM.
|
||||
|
||||
### Prérequis
|
||||
|
||||
- Python 3.11.2
|
||||
- flask : 3.0.2
|
||||
- requests : 2.31.0
|
||||
- bootstrap : 4.3.1
|
@ -0,0 +1,18 @@
|
||||
import requests
|
||||
from flask import Flask, render_template
|
||||
from fonctions import *
|
||||
|
||||
|
||||
app = Flask(__name__)
|
||||
|
||||
@app.route("/")
|
||||
def index():
|
||||
return render_template("index.html")
|
||||
|
||||
@app.route("/livres", methods=("GET", "POST"))
|
||||
def livres():
|
||||
datas = get_books()
|
||||
return render_template("livres.html", datas=datas)
|
||||
|
||||
if __name__ == " __main__":
|
||||
app.run()
|
@ -0,0 +1,55 @@
|
||||
import requests, json, ipaddress, random
|
||||
from flask import request
|
||||
|
||||
def get_headers():
|
||||
|
||||
ip = []
|
||||
|
||||
for i in range(0, 4):
|
||||
ip.append(random.randint(0, 254))
|
||||
|
||||
random_ip = ''
|
||||
for i in range(0, 3):
|
||||
random_ip += str(ip[i]) + '.'
|
||||
|
||||
random_ip += str(ip[3])
|
||||
|
||||
headers = {"X-Forwarded-For": random_ip}
|
||||
|
||||
return headers
|
||||
|
||||
class Livre:
|
||||
def __init__(self, title, author, publish, isbn, img_url):
|
||||
self.title = title
|
||||
self.author = author
|
||||
self.publish = publish
|
||||
self.isbn = isbn
|
||||
self.img_url = img_url
|
||||
|
||||
def get_books():
|
||||
|
||||
livres = []
|
||||
headers = get_headers()
|
||||
|
||||
# La condition if permet de n'afficher du contenue de l'API que lorsqu'il y a une requête qui est effectué.
|
||||
if request.method == "POST":
|
||||
choix = request.form["choix"]
|
||||
|
||||
# Concaténations a l'url de l'API du choix de l'utilisateur reçu via request.form et on choisi les informations que nous souhaitons récuperer.
|
||||
url = "https://openlibrary.org/search.json?q=" + choix + "&fields=title,author_name,first_publish_year,isbn"
|
||||
response = requests.get(url, headers)
|
||||
|
||||
# Transformation des données reçu de l'API en objet JSON pour les avoir sous forme clé/valeur.
|
||||
datas = json.loads(response.text)
|
||||
|
||||
for e in datas["docs"]:
|
||||
# A l'aide du constructeur de la classe Livre on affine les données reçu et on concaténe isbn a l'url images.
|
||||
livre = Livre(e["title"], e["author_name"][0], e["first_publish_year"], e["isbn"][0], "https://covers.openlibrary.org/b/isbn/" + e["isbn"][0] + "-L.jpg")
|
||||
|
||||
# Informations ajouté au dictionnaire livres definit plus haut.
|
||||
livres.append(livre)
|
||||
else:
|
||||
print("Pas de requête effectué")
|
||||
livres.append("No datas")
|
||||
|
||||
return livres
|
@ -0,0 +1,4 @@
|
||||
gunicorn==22.0.0
|
||||
packaging==24.0
|
||||
requests==2.31.0
|
||||
flask==3.0.2
|
@ -0,0 +1,49 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta>
|
||||
<title>Projet API</title>
|
||||
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css"
|
||||
integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
|
||||
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js"
|
||||
integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo"
|
||||
crossorigin="anonymous"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/popper.js@1.14.7/dist/umd/popper.min.js"
|
||||
integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1"
|
||||
crossorigin="anonymous"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@4.3.1/dist/js/bootstrap.min.js"
|
||||
integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM"
|
||||
crossorigin="anonymous"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<nav class="navbar navbar-expand-lg navbar-light bg-light">
|
||||
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent"
|
||||
aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
|
||||
<div class="collapse navbar-collapse" id="navbarSupportedContent">
|
||||
<ul class="navbar-nav m-auto">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" style="font-size: 24px; padding-left: 40px;"
|
||||
href="{{url_for('index')}}">Home</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" style="font-size: 24px; padding-left: 40px;"
|
||||
href="{{url_for('livres')}}">Books</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</nav>
|
||||
<div class="text-center jumbotron">
|
||||
{% block content %}
|
||||
{% endblock %}
|
||||
</div>
|
||||
<footer class="text-center">
|
||||
<img src="https://git.legaragenumerique.fr/assets/img/logo.svg" alt="Logo garage numerique">
|
||||
</footer>
|
||||
</body>
|
||||
|
||||
</html>
|
@ -0,0 +1,34 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block content %}
|
||||
<div>
|
||||
<div>
|
||||
<div class="text-center">
|
||||
<h1 class="display-3 m-5">💻 Welcome!</h1>
|
||||
</div>
|
||||
<div class="text-center p-5" style="background-color: white; margin-top: 100px;">
|
||||
<p class="mt-2" style="font-size: 2em;"> 💡 Find your new favorite book among several provided categories. 💡</p>
|
||||
<hr style="margin: 60px 0;">
|
||||
|
||||
<div class="mt-5 p-4 d-flex justify-content-center">
|
||||
<div class="col-6" style="border-right: 1px solid grey;">
|
||||
<ul style="list-style: none;">
|
||||
<li style="font-size: 1.5em;" class="mt-4"></li>
|
||||
<li style="font-size: 1.5em;" class="mt-4">★ Horror </li>
|
||||
<li style="font-size: 1.5em;" class="mt-4">★ Thriller </li>
|
||||
<li style="font-size: 1.5em;" class="mt-4">★ Science Fisction </li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="col-6">
|
||||
<ul style="list-style: none;">
|
||||
<li style="font-size: 1.5em;" class="mt-4">★ Fiction </li>
|
||||
<li style="font-size: 1.5em;" class="mt-4">★ Romance </li>
|
||||
<li style="font-size: 1.5em;" class="mt-4">★ Fantasy </li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
@ -0,0 +1,47 @@
|
||||
{% extends "base.html" %}
|
||||
{% block content %}
|
||||
<div>
|
||||
<div>
|
||||
<h1 class="mt-4" style="font-size: 44px">Books 📚</h1>
|
||||
<p class="mt-4" style="font-size: 20px">Choose a category and see our selection</p>
|
||||
</div>
|
||||
<!-- Formulaire d'affichage des buttons et envoi de l'information selectionné par l'utilisateur. -->
|
||||
<form action="/livres" method="POST" class="m-5 text-center">
|
||||
<button type="submit" name="choix" value="horror" class="btn btn-outline-primary m-3">Horror</button>
|
||||
<button type="submit" name="choix" value="fantasy" class="btn btn-outline-primary m-3">Fantasy</button>
|
||||
<button type="submit" name="choix" value="thriller" class="btn btn-outline-primary m-3">Thriller</button>
|
||||
<button type="submit" name="choix" value="poetry" class="btn btn-outline-primary m-3">Poetry</button>
|
||||
<button type="submit" name="choix" value="fiction" class="btn btn-outline-primary m-3">Fiction</button>
|
||||
<button type="submit" name="choix" value="romance" class="btn btn-outline-primary m-3">Romance</button>
|
||||
<button type="submit" name="choix" value="sf" class="btn btn-outline-primary m-3">Science Fisction</button>
|
||||
<button type="submit" name="choix" value="historical_fiction" class="btn btn-outline-primary m-3">Historical Fiction</button>
|
||||
<button type="submit" name="choix" value="humor" class="btn btn-outline-primary m-3">Humor</button>
|
||||
</form>
|
||||
|
||||
{% if datas[0] != "No datas" %}
|
||||
<div class="container">
|
||||
<div class=" row">
|
||||
<!-- cette boucle me permet d'afficher chaque element de datas dans une card -->
|
||||
{% for elem in datas %}
|
||||
<div class="col-12 col-md-4">
|
||||
<div class="card mb-3" style="max-width: 440px;">
|
||||
<div class="row no-gutters">
|
||||
<div class="col-md-4">
|
||||
<img src={{elem.img_url}} class="card-img" alt="There is no available image for this book!">
|
||||
</div>
|
||||
<div class="col-md-8">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">{{ elem.title }}</h5>
|
||||
<p class="card-text">{{ elem.author }}</p>
|
||||
<p class="card-text"><small class="text-muted">{{ elem.publish }}</small></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endblock %}
|
Loading…
Reference in New Issue