From 26bcff61abbc44028557a06962adbb82665ca6be Mon Sep 17 00:00:00 2001
From: Ewwweee
Date: Wed, 25 Sep 2024 09:54:40 +0200
Subject: [PATCH 01/12] Question 1&2
---
...rchi-distribuees-Movie-1.0.0-resolved.yaml | 63 ++++++++-
movie/databases/movies.json | 53 +-------
movie/movie.py | 127 ++++++++++++++++++
movie/templates/movies_per_ratings.html | 14 ++
4 files changed, 203 insertions(+), 54 deletions(-)
create mode 100644 movie/templates/movies_per_ratings.html
diff --git a/movie/UE-archi-distribuees-Movie-1.0.0-resolved.yaml b/movie/UE-archi-distribuees-Movie-1.0.0-resolved.yaml
index 73dfb68..f3517b9 100644
--- a/movie/UE-archi-distribuees-Movie-1.0.0-resolved.yaml
+++ b/movie/UE-archi-distribuees-Movie-1.0.0-resolved.yaml
@@ -2,7 +2,6 @@
openapi: 3.0.3
info:
title: Movie API
- summary: This is the API of the Movie service
description: This is the API of the Movie service, it should be much much much much much much much much much much much much much much much much much much much much much longer
contact:
name: Helene Coullon
@@ -173,12 +172,72 @@ paths:
schema:
maximum: 10
minimum: 0
- type: integer
+ type: number
responses:
"200":
description: rate updated
"400":
description: movie ID not found
+ /help:
+ get:
+ tags:
+ - admins
+ - developers
+ summary: give all the entries of this microservice
+ description: give all the entries of this microservice
+ operationId: help
+ responses:
+ "200":
+ description: return JSON
+ /movies_per_ratings:
+ get:
+ tags:
+ - developers
+ summary: gives the list of the movies sorted by decreasing rate
+ description: gives the list of the movies sorted by decreasing rate
+ operationId: get_movies_classify_per_ratings
+ responses:
+ "200":
+ description: return a HTML page
+ /directors:
+ get:
+ tags:
+ - developers
+ summary: gives all the directors who have directed a movie
+ description: gives all the directors who have directed a movie
+ operationId: get_directors
+ responses:
+ "200":
+ description: return a HTML page
+ /directors/{movie_id}{director_name}:
+ put:
+ tags:
+ - developers
+ summary: change the director of the movie movie_id
+ description: change the director of the movie movie_id
+ operationId: update_director_movie
+ parameters:
+ - name: director_name
+ in: path
+ description: director name
+ required: true
+ style: simple
+ explode: false
+ schema:
+ type: string
+ - name: movie_id
+ in: path
+ description: movie id
+ required: true
+ style: simple
+ explode: false
+ schema:
+ type: string
+ responses:
+ "200":
+ description: return a HTML page
+ "400":
+ description: director not found
components:
schemas:
AllMovies:
diff --git a/movie/databases/movies.json b/movie/databases/movies.json
index 260bc88..5584a0c 100644
--- a/movie/databases/movies.json
+++ b/movie/databases/movies.json
@@ -1,52 +1 @@
-{
- "movies": [
- {
- "title": "The Good Dinosaur",
- "rating": 7.4,
- "director": "Peter Sohn",
- "id": "720d006c-3a57-4b6a-b18f-9b713b073f3c"
- },
- {
- "title": "The Martian",
- "rating": 8.2,
- "director": "Ridley Scott",
- "id": "a8034f44-aee4-44cf-b32c-74cf452aaaae"
- },
- {
- "title": "The Night Before",
- "rating": 7.4,
- "director": "Jonathan Levine",
- "id": "96798c08-d19b-4986-a05d-7da856efb697"
- },
- {
- "title": "Creed",
- "rating": 8.8,
- "director": "Ryan Coogler",
- "id": "267eedb8-0f5d-42d5-8f43-72426b9fb3e6"
- },
- {
- "title": "Victor Frankenstein",
- "rating": 6.4,
- "director": "Paul McGuigan",
- "id": "7daf7208-be4d-4944-a3ae-c1c2f516f3e6"
- },
- {
- "title": "The Danish Girl",
- "rating": 5.3,
- "director": "Tom Hooper",
- "id": "276c79ec-a26a-40a6-b3d3-fb242a5947b6"
- },
- {
- "title": "Spectre",
- "rating": 7.1,
- "director": "Sam Mendes",
- "id": "39ab85e5-5e8e-4dc5-afea-65dc368bd7ab"
- },
- {
- "title": "Test",
- "rating": 1.2,
- "director": "Someone",
- "id": "xxx"
- }
- ]
-}
\ No newline at end of file
+{"movies": [{"title": "The Good Dinosaur", "rating": 7.4, "director": "Peter Sohn", "id": "720d006c-3a57-4b6a-b18f-9b713b073f3c"}, {"title": "The Martian", "rating": 8.2, "director": "Ridley Scott", "id": "a8034f44-aee4-44cf-b32c-74cf452aaaae"}, {"title": "The Night Before", "rating": 7.4, "director": "Jonathan Levine", "id": "96798c08-d19b-4986-a05d-7da856efb697"}, {"title": "Creed", "rating": 8.8, "director": "Ryan Coogler", "id": "267eedb8-0f5d-42d5-8f43-72426b9fb3e6"}, {"title": "Victor Frankenstein", "rating": 6.4, "director": "Paul McGuigan", "id": "7daf7208-be4d-4944-a3ae-c1c2f516f3e6"}, {"title": "The Danish Girl", "rating": 5.3, "director": "Tom Hooper", "id": "276c79ec-a26a-40a6-b3d3-fb242a5947b6"}, {"title": "Spectre", "rating": 7.1, "director": "Sam Mendes", "id": "39ab85e5-5e8e-4dc5-afea-65dc368bd7ab"}, {"title": "Test", "rating": 1.2, "director": "Someone", "id": "xxx"}, {"title": "Guardians of the Galaxy", "rating": 1.2, "director": "James Gun", "id": "7cv89fs5-7845-2sc3-6942-cdf4qz5rz"}, {"title": "Goo", "rating": 1.2, "director": "gooooooooo", "id": "7cv89fs5-7845-2sc3-6942-cds4qz5rz"}]}
\ No newline at end of file
diff --git a/movie/movie.py b/movie/movie.py
index a0ddb16..cefebd7 100644
--- a/movie/movie.py
+++ b/movie/movie.py
@@ -16,6 +16,133 @@
def home():
return make_response("Welcome to the Movie service!
",200)
+@app.route("/template", methods=['GET'])
+def template():
+ return make_response(render_template('index.html', body_text='This is my HTML template for Movie service'),200)
+
+@app.route("/json", methods=['GET'])
+def get_json():
+ res = make_response(jsonify(movies), 200)
+ return res
+
+@app.route("/movies/", methods=['GET'])
+def get_movie_byid(movieid):
+ for movie in movies:
+ if str(movie["id"]) == str(movieid):
+ res = make_response(jsonify(movie),200)
+ return res
+ return make_response(jsonify({"error":"Movie ID not found"}),400)
+
+@app.route("/moviesbytitle", methods=['GET'])
+def get_movie_bytitle():
+ json = ""
+ print("request.args : ", request.args)
+ if request.args:
+ req = request.args
+ print("request.args : ", req)
+ for movie in movies:
+ if str(movie["title"]) == str(req["title"]):
+ json = movie
+
+ if not json:
+ res = make_response(jsonify({"error":"movie title not found"}),400)
+ else:
+ res = make_response(jsonify(json),200)
+ return res
+
+{
+ "title": "Test",
+ "rating": 1.2,
+ "director": "Someone",
+ "id":"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxx"
+}
+
+@app.route("/addmovie/", methods=['POST'])
+def add_movie(movieid):
+ req = request.get_json()
+ print("req : ", req)
+ for movie in movies:
+ if str(movie["id"]) == str(movieid):
+ return make_response(jsonify({"error":"movie ID already exists"}),409)
+
+ movies.append(req)
+ write(movies)
+ res = make_response(jsonify({"message":"movie added"}),200)
+ return res
+
+@app.route("/movies//", methods=['PUT'])
+def update_movie_rating(movieid, rate):
+ for movie in movies:
+ if str(movie["id"]) == str(movieid):
+ movie["rating"] = rate
+ res = make_response(jsonify(movie),200)
+ return res
+
+ res = make_response(jsonify({"error":"movie ID not found"}),201)
+ return res
+
+@app.route("/movies/", methods=['DELETE'])
+def del_movie(movieid):
+ for movie in movies:
+ if str(movie["id"]) == str(movieid):
+ movies.remove(movie)
+ return make_response(jsonify(movie),200)
+
+ res = make_response(jsonify({"error":"movie ID not found"}),400)
+ return res
+
+def write(movies):
+ with open('{}/databases/movies.json'.format("."), 'w') as f:
+
+ json.dump({"movies" : movies}, f)
+
+#####################################
+##### ADDED #####
+#####################################
+all_methods = {
+ "GET": ["/","/help","/template","/json","/movies/","/moviesbytitle","/movies_per_ratings","/directors"],
+ "POST": ["/addmovie/"],
+ "PUT": ["/movies//","/directors//"],
+ "DELETE": ["/movies/"]
+}
+
+@app.route("/help",methods=["GET"])
+def help():
+ return all_methods
+
+@app.route("/movies_per_ratings",methods=["GET"])
+def get_movies_classify_per_ratings():
+ """Function which sort the movies by ratings"""
+ list_movies:list = []
+
+ # We get the list of movies associated with there ranking
+ for movie in movies:
+ list_movies.append([movie["rating"],movie["title"]])
+ list_movies.sort()
+ body_text = ""
+ # We format the text to create a list in the html screen
+ for elem in list_movies:
+ body_text += f"{elem[1]} : {elem[0]} \n"
+ return make_response(render_template('movies_per_ratings.html', body_text=body_text),200)
+
+@app.route("/directors",methods=["GET"])
+def get_all_directors():
+ """This function get the directors of all movies"""
+ list_directors = []
+ for movie in movies:
+ list_directors.append(movie["director"])
+ return jsonify({"list_directors" : list_directors})
+
+@app.route("/directors//",methods=["PUT"])
+def update_director_movie(director_name:str,movie_id:str):
+ """This function change the director name of the movie whixh has as id movie_id"""
+ for movie in movies:
+ if str(movie["id"])==movie_id:
+ movie["director"] = director_name
+ res = make_response(jsonify(movie),200)
+ return res
+ return make_response(jsonify({"error":"movie ID not found"}),201)
+
if __name__ == "__main__":
#p = sys.argv[1]
print("Server running in port %s"%(PORT))
diff --git a/movie/templates/movies_per_ratings.html b/movie/templates/movies_per_ratings.html
new file mode 100644
index 0000000..e865a86
--- /dev/null
+++ b/movie/templates/movies_per_ratings.html
@@ -0,0 +1,14 @@
+
+
+
+
+ Ranking of the best movies
+
+
+ Movies sorted by rank
+
+ {{ body_text | safe}}
+
+
+
+
\ No newline at end of file
From b7fd685c7fc8b5484b2d2c00e2892e7255c0ad88 Mon Sep 17 00:00:00 2001
From: Cordoncharge83 <146195205+Cordoncharge83@users.noreply.github.com>
Date: Wed, 25 Sep 2024 10:32:45 +0200
Subject: [PATCH 02/12] Add : microservice Times
---
showtime/showtime.py | 15 +++++++++++++++
1 file changed, 15 insertions(+)
diff --git a/showtime/showtime.py b/showtime/showtime.py
index 6cf26fd..41e977d 100644
--- a/showtime/showtime.py
+++ b/showtime/showtime.py
@@ -14,6 +14,21 @@
def home():
return "Welcome to the Showtime service!
"
+@app.route("/showtimes", methods=['GET'])
+def get_showtimes():
+ result = make_response(jsonify(schedule),200)
+ return result
+
+@app.route("/showmovies/", methods=['GET'])
+def get_schedule_bydate(date):
+ for showtime in schedule:
+ if str(showtime["date"]) == str(date):
+ result = make_response(jsonify(showtime),200)
+ return result
+
+ return make_response(jsonify({"error":"Date not available"}),400)
+
+
if __name__ == "__main__":
print("Server running in port %s"%(PORT))
app.run(host=HOST, port=PORT)
From e34c406eb911e401d8c4d6f3b558a3ae8e937f91 Mon Sep 17 00:00:00 2001
From: Cordoncharge83 <146195205+Cordoncharge83@users.noreply.github.com>
Date: Wed, 25 Sep 2024 10:41:32 +0200
Subject: [PATCH 03/12] Add : commentaires
---
showtime/showtime.py | 3 +++
1 file changed, 3 insertions(+)
diff --git a/showtime/showtime.py b/showtime/showtime.py
index 41e977d..700d137 100644
--- a/showtime/showtime.py
+++ b/showtime/showtime.py
@@ -14,11 +14,14 @@
def home():
return "Welcome to the Showtime service!
"
+# Fonction pour retourner toute la base de données times : La liste des
+# dates avec les films qui seraient projetés
@app.route("/showtimes", methods=['GET'])
def get_showtimes():
result = make_response(jsonify(schedule),200)
return result
+# Fonction pour retourner la liste des films projetés pour une date donnée
@app.route("/showmovies/", methods=['GET'])
def get_schedule_bydate(date):
for showtime in schedule:
From 3a5390c39f6a99d2d7dbc3cafcb940198069f273 Mon Sep 17 00:00:00 2001
From: Ewwweee
Date: Wed, 25 Sep 2024 11:23:36 +0200
Subject: [PATCH 04/12] Q4 V1
---
booking/booking.py | 49 +++++++++++++++++++++++++++++++++
booking/databases/bookings.json | 40 +--------------------------
2 files changed, 50 insertions(+), 39 deletions(-)
diff --git a/booking/booking.py b/booking/booking.py
index 267e439..9724090 100644
--- a/booking/booking.py
+++ b/booking/booking.py
@@ -15,7 +15,56 @@
def home():
return "Welcome to the Booking service!
"
+@app.route("/bookings",methods=["GET"])
+def get_json():
+ """This function return all the movie's reservations"""
+ return make_response(jsonify(bookings))
+@app.route("/bookings/",methods=["GET"])
+def get_booking_for_user(userid:str):
+ """This function get all the bookings made by the user user_id """
+ for reservation in bookings:
+ if userid == reservation["userid"]: # We found the good user
+ return make_response(jsonify(reservation["dates"]),200)
+ # We didn't find the user so we return an error
+ return make_response(jsonify({"error": "bad input parameter"}),400)
+
+@app.route("/bookings/",methods=["POST"])
+def add_booking_byuser(userid:str):
+ """This function get all the bookings made by the user user_id """
+ # We check if the user gave a new movie
+ if request.args:
+ req = request.args
+ for reservation in bookings:
+ if userid == reservation["userid"]: # We found the good user
+ for date in reservation["dates"]:
+ if date["date"] == req["date"]:
+ # We need to check if the user didn't already book this movie
+ if req["movieid"] in date["movies"]:
+ return make_response(jsonify({"error": "an existing item already exists"}),409)
+ else:
+ # We add the movie
+ date["movies"].append(req["movieid"])
+ # We write in the database
+ write(bookings)
+ res = make_response(jsonify({"message":"Booking added"}),200)
+ return res
+
+ #It is a new date
+ reservation["dates"].append({"date":req["date"],"movies":[req["movieid"]]})
+ # We write in the database
+ write(bookings)
+ res = make_response(jsonify({"message":"Booking created"}),200)
+ return res
+
+ # We didn't find the user so we return an error
+ return make_response(jsonify({"error": "bad input parameter"}),201)
+ return make_response(jsonify({"error": "Wrong input"}),400)
+
+def write(movies):
+ with open('{}/databases/bookings.json'.format("."), 'w') as f:
+
+ json.dump({"movies" : movies}, f)
if __name__ == "__main__":
print("Server running in port %s"%(PORT))
app.run(host=HOST, port=PORT)
diff --git a/booking/databases/bookings.json b/booking/databases/bookings.json
index 55e4853..30d03a6 100644
--- a/booking/databases/bookings.json
+++ b/booking/databases/bookings.json
@@ -1,39 +1 @@
-{
- "bookings": [
- {
- "userid": "chris_rivers",
- "dates": [
- {
- "date": "20151201",
- "movies": ["267eedb8-0f5d-42d5-8f43-72426b9fb3e6"]
- }
- ]
- },
- {
- "userid": "garret_heaton",
- "dates": [
- {
- "date": "20151201",
- "movies": ["267eedb8-0f5d-42d5-8f43-72426b9fb3e6"]
- },
- {
- "date": "20151202",
- "movies": ["276c79ec-a26a-40a6-b3d3-fb242a5947b6"]
- }
- ]
- },
- {
- "userid": "dwight_schrute",
- "dates": [
- {
- "date": "20151201",
- "movies": ["7daf7208-be4d-4944-a3ae-c1c2f516f3e6","267eedb8-0f5d-42d5-8f43-72426b9fb3e6"]
- },
- {
- "date": "20151205",
- "movies": ["a8034f44-aee4-44cf-b32c-74cf452aaaae","276c79ec-a26a-40a6-b3d3-fb242a5947b6"]
- }
- ]
- }
- ]
-}
\ No newline at end of file
+{"movies": [{"userid": "chris_rivers", "dates": [{"date": "20151201", "movies": ["267eedb8-0f5d-42d5-8f43-72426b9fb3e6"]}]}, {"userid": "garret_heaton", "dates": [{"date": "20151201", "movies": ["267eedb8-0f5d-42d5-8f43-72426b9fb3e6"]}, {"date": "20151202", "movies": ["276c79ec-a26a-40a6-b3d3-fb242a5947b6"]}]}, {"userid": "dwight_schrute", "dates": [{"date": "20151201", "movies": ["7daf7208-be4d-4944-a3ae-c1c2f516f3e6", "267eedb8-0f5d-42d5-8f43-72426b9fb3e6"]}, {"date": "20151205", "movies": ["a8034f44-aee4-44cf-b32c-74cf452aaaae", "276c79ec-a26a-40a6-b3d3-fb242a5947b6", "276c79ec-a26a-40a6-b3d3-fb242a5947b8"]}, {"date": "20151210", "movies": ["276c79ec-a26a-40a6-b3d3-fb242a5947b6"]}]}]}
\ No newline at end of file
From e0f8022e48aced69d544c50d9fab83df8f5c2302 Mon Sep 17 00:00:00 2001
From: Cordoncharge83 <146195205+Cordoncharge83@users.noreply.github.com>
Date: Wed, 25 Sep 2024 12:03:55 +0200
Subject: [PATCH 05/12] Add : Verify booking date from showtimes
---
booking/booking.py | 51 +++++++++++++++++-----------
booking/databases/bookings.json | 59 ++++++++++++++++++++++++++++++++-
2 files changed, 89 insertions(+), 21 deletions(-)
diff --git a/booking/booking.py b/booking/booking.py
index 9724090..7574186 100644
--- a/booking/booking.py
+++ b/booking/booking.py
@@ -11,6 +11,15 @@
with open('{}/databases/bookings.json'.format("."), "r") as jsf:
bookings = json.load(jsf)["bookings"]
+with open("C:/ProgramData/Projets/ue-CONT/TP1/UE-AD-A1-REST/showtime/databases/times.json".format("."), "r") as jsf:
+ schedule = json.load(jsf)["schedule"]
+
+# We define a list of all the dates available in the schedule :
+dates = []
+for show in schedule :
+ dates.append(str(show["date"]))
+print(dates)
+
@app.route("/", methods=['GET'])
def home():
return "Welcome to the Booking service!
"
@@ -37,26 +46,28 @@ def add_booking_byuser(userid:str):
req = request.args
for reservation in bookings:
if userid == reservation["userid"]: # We found the good user
- for date in reservation["dates"]:
- if date["date"] == req["date"]:
- # We need to check if the user didn't already book this movie
- if req["movieid"] in date["movies"]:
- return make_response(jsonify({"error": "an existing item already exists"}),409)
- else:
- # We add the movie
- date["movies"].append(req["movieid"])
- # We write in the database
- write(bookings)
- res = make_response(jsonify({"message":"Booking added"}),200)
- return res
-
- #It is a new date
- reservation["dates"].append({"date":req["date"],"movies":[req["movieid"]]})
- # We write in the database
- write(bookings)
- res = make_response(jsonify({"message":"Booking created"}),200)
- return res
-
+ if req["date"] in dates : # Check if there are movies shown during that date
+ for date in reservation["dates"]:
+ if date["date"] == req["date"] :
+ # We need to check if the user didn't already book this movie
+ if req["movieid"] in date["movies"]:
+ return make_response(jsonify({"error": "an existing item already exists"}),409)
+ else:
+ # We add the movie
+ date["movies"].append(req["movieid"])
+ # We write in the database
+ write(bookings)
+ res = make_response(jsonify({"message":"Booking added"}),200)
+ return res
+ #It is a new date
+ reservation["dates"].append({"date":req["date"],"movies":[req["movieid"]]})
+ # We write in the database
+ write(bookings)
+ res = make_response(jsonify({"message":"Booking created"}),200)
+ return res
+ else :
+ return make_response(jsonify({"error": "bad input : date is unavailable"}),202)
+
# We didn't find the user so we return an error
return make_response(jsonify({"error": "bad input parameter"}),201)
return make_response(jsonify({"error": "Wrong input"}),400)
diff --git a/booking/databases/bookings.json b/booking/databases/bookings.json
index 30d03a6..d6eaa20 100644
--- a/booking/databases/bookings.json
+++ b/booking/databases/bookings.json
@@ -1 +1,58 @@
-{"movies": [{"userid": "chris_rivers", "dates": [{"date": "20151201", "movies": ["267eedb8-0f5d-42d5-8f43-72426b9fb3e6"]}]}, {"userid": "garret_heaton", "dates": [{"date": "20151201", "movies": ["267eedb8-0f5d-42d5-8f43-72426b9fb3e6"]}, {"date": "20151202", "movies": ["276c79ec-a26a-40a6-b3d3-fb242a5947b6"]}]}, {"userid": "dwight_schrute", "dates": [{"date": "20151201", "movies": ["7daf7208-be4d-4944-a3ae-c1c2f516f3e6", "267eedb8-0f5d-42d5-8f43-72426b9fb3e6"]}, {"date": "20151205", "movies": ["a8034f44-aee4-44cf-b32c-74cf452aaaae", "276c79ec-a26a-40a6-b3d3-fb242a5947b6", "276c79ec-a26a-40a6-b3d3-fb242a5947b8"]}, {"date": "20151210", "movies": ["276c79ec-a26a-40a6-b3d3-fb242a5947b6"]}]}]}
\ No newline at end of file
+{
+ "bookings": [
+ {
+ "userid": "chris_rivers",
+ "dates": [
+ {
+ "date": "20151201",
+ "movies": [
+ "267eedb8-0f5d-42d5-8f43-72426b9fb3e6"
+ ]
+ }
+ ]
+ },
+ {
+ "userid": "garret_heaton",
+ "dates": [
+ {
+ "date": "20151201",
+ "movies": [
+ "267eedb8-0f5d-42d5-8f43-72426b9fb3e6"
+ ]
+ },
+ {
+ "date": "20151202",
+ "movies": [
+ "276c79ec-a26a-40a6-b3d3-fb242a5947b6"
+ ]
+ }
+ ]
+ },
+ {
+ "userid": "dwight_schrute",
+ "dates": [
+ {
+ "date": "20151201",
+ "movies": [
+ "7daf7208-be4d-4944-a3ae-c1c2f516f3e6",
+ "267eedb8-0f5d-42d5-8f43-72426b9fb3e6"
+ ]
+ },
+ {
+ "date": "20151205",
+ "movies": [
+ "a8034f44-aee4-44cf-b32c-74cf452aaaae",
+ "276c79ec-a26a-40a6-b3d3-fb242a5947b6",
+ "276c79ec-a26a-40a6-b3d3-fb242a5947b8"
+ ]
+ },
+ {
+ "date": "20151210",
+ "movies": [
+ "276c79ec-a26a-40a6-b3d3-fb242a5947b6"
+ ]
+ }
+ ]
+ }
+ ]
+}
\ No newline at end of file
From 4f110e1dbb4796880a0cdb89489d1dcd1499dbc8 Mon Sep 17 00:00:00 2001
From: Ewwweee
Date: Wed, 25 Sep 2024 14:42:50 +0200
Subject: [PATCH 06/12] Debu 6
---
...hi-distribuees-Booking-1.0.0-resolved.yaml | 4 +++
booking/databases/bookings.json | 2 +-
movie/movie.py | 2 --
user/user.py | 27 +++++++++++++++++++
4 files changed, 32 insertions(+), 3 deletions(-)
diff --git a/booking/UE-archi-distribuees-Booking-1.0.0-resolved.yaml b/booking/UE-archi-distribuees-Booking-1.0.0-resolved.yaml
index b53555c..bae0c98 100644
--- a/booking/UE-archi-distribuees-Booking-1.0.0-resolved.yaml
+++ b/booking/UE-archi-distribuees-Booking-1.0.0-resolved.yaml
@@ -99,6 +99,10 @@ paths:
application/json:
schema:
$ref: '#/components/schemas/BookingsUser'
+ "201":
+ description: 'bad input parameter'
+ "400":
+ description: 'Wrong input"'
"409":
description: an existing item already exists
components:
diff --git a/booking/databases/bookings.json b/booking/databases/bookings.json
index 30d03a6..39b3b4a 100644
--- a/booking/databases/bookings.json
+++ b/booking/databases/bookings.json
@@ -1 +1 @@
-{"movies": [{"userid": "chris_rivers", "dates": [{"date": "20151201", "movies": ["267eedb8-0f5d-42d5-8f43-72426b9fb3e6"]}]}, {"userid": "garret_heaton", "dates": [{"date": "20151201", "movies": ["267eedb8-0f5d-42d5-8f43-72426b9fb3e6"]}, {"date": "20151202", "movies": ["276c79ec-a26a-40a6-b3d3-fb242a5947b6"]}]}, {"userid": "dwight_schrute", "dates": [{"date": "20151201", "movies": ["7daf7208-be4d-4944-a3ae-c1c2f516f3e6", "267eedb8-0f5d-42d5-8f43-72426b9fb3e6"]}, {"date": "20151205", "movies": ["a8034f44-aee4-44cf-b32c-74cf452aaaae", "276c79ec-a26a-40a6-b3d3-fb242a5947b6", "276c79ec-a26a-40a6-b3d3-fb242a5947b8"]}, {"date": "20151210", "movies": ["276c79ec-a26a-40a6-b3d3-fb242a5947b6"]}]}]}
\ No newline at end of file
+{"bookings":{"movies": [{"userid": "chris_rivers", "dates": [{"date": "20151201", "movies": ["267eedb8-0f5d-42d5-8f43-72426b9fb3e6"]}]}, {"userid": "garret_heaton", "dates": [{"date": "20151201", "movies": ["267eedb8-0f5d-42d5-8f43-72426b9fb3e6"]}, {"date": "20151202", "movies": ["276c79ec-a26a-40a6-b3d3-fb242a5947b6"]}]}, {"userid": "dwight_schrute", "dates": [{"date": "20151201", "movies": ["7daf7208-be4d-4944-a3ae-c1c2f516f3e6", "267eedb8-0f5d-42d5-8f43-72426b9fb3e6"]}, {"date": "20151205", "movies": ["a8034f44-aee4-44cf-b32c-74cf452aaaae", "276c79ec-a26a-40a6-b3d3-fb242a5947b6", "276c79ec-a26a-40a6-b3d3-fb242a5947b8"]}, {"date": "20151210", "movies": ["276c79ec-a26a-40a6-b3d3-fb242a5947b6"]}]}]}}
\ No newline at end of file
diff --git a/movie/movie.py b/movie/movie.py
index cefebd7..f255735 100644
--- a/movie/movie.py
+++ b/movie/movie.py
@@ -36,10 +36,8 @@ def get_movie_byid(movieid):
@app.route("/moviesbytitle", methods=['GET'])
def get_movie_bytitle():
json = ""
- print("request.args : ", request.args)
if request.args:
req = request.args
- print("request.args : ", req)
for movie in movies:
if str(movie["title"]) == str(req["title"]):
json = movie
diff --git a/user/user.py b/user/user.py
index 8a17e84..df49538 100644
--- a/user/user.py
+++ b/user/user.py
@@ -7,6 +7,8 @@
PORT = 3203
HOST = '0.0.0.0'
+BOOKING_PATH="http://localhost:3201"
+MOVIE_PATH="http://localhost:3200"
with open('{}/databases/users.json'.format("."), "r") as jsf:
users = json.load(jsf)["users"]
@@ -15,6 +17,31 @@
def home():
return "Welcome to the User service!
"
+@app.route("/movies_per_ratings",methods=["GET"])
+def get_movies_per_ratings():
+ """This function will get all the movies available sorted by rating"""
+ return requests.request("GET", MOVIE_PATH +"/movies_per_ratings")
+
+@app.route("/movies_available/",methods=["GET"])
+def get_movies_available_at_date(date:str):
+ """This function shows what are the movies available at the date date"""
+ pass
+
+@app.route("/book_a_movie//")
+def book_the_movie(moviename:str,username:str):
+ """This function books the movie name moviename for the user username"""
+ pass
+
+@app.route("/booking_made/",methods=["GET"])
+def get_booking_made(username:str):
+ """This function will get all the booking already made by username"""
+ return requests.request("GET", BOOKING_PATH + "/bookings/" + convert_username_id(username))
+
+def convert_username_id(username:str):
+ """This get the id corresponding to the user username"""
+ for user in users:
+ if user["name"]==username:
+ return user["id"]
if __name__ == "__main__":
print("Server running in port %s"%(PORT))
From 39a481642547dbe41c163673ca21ef2c019803f2 Mon Sep 17 00:00:00 2001
From: Ewwweee
Date: Fri, 27 Sep 2024 15:17:39 +0200
Subject: [PATCH 07/12] Fin TP Reset
---
.gitignore | 179 ++++++++
...hi-distribuees-Booking-1.0.0-resolved.yaml | 39 ++
booking/booking.py | 68 +++-
booking/databases/bookings.json | 28 +-
...rchi-distribuees-Movie-1.0.0-resolved.yaml | 27 +-
movie/databases/movies.json | 53 ++-
movie/movie.py | 18 +-
showtime/showtime.py | 8 +-
...chi-distribuees-User-1.0.0.0.resolved.yaml | 171 ++++++++
user/templates/add_a_booking.html | 11 +
user/templates/booking_made.html | 14 +
.../templates/error_get_booking_per_user.html | 10 +
.../get_movies_available_at_date.html | 14 +
.../templates/movies_per_ratings.html | 0
user/templates/response_add_booking.html | 12 +
user/user.py | 88 +++-
venv1/Scripts/Activate.ps1 | 384 ++++++++++++++++++
venv1/Scripts/activate | 66 +++
venv1/Scripts/activate.bat | 33 ++
venv1/Scripts/deactivate.bat | 21 +
venv1/Scripts/easy_install-3.9.exe | Bin 0 -> 106432 bytes
venv1/Scripts/easy_install.exe | Bin 0 -> 106432 bytes
venv1/Scripts/flask.exe | Bin 0 -> 106410 bytes
venv1/Scripts/normalizer.exe | Bin 0 -> 106435 bytes
venv1/Scripts/pip.exe | Bin 0 -> 106423 bytes
venv1/Scripts/pip3.9.exe | Bin 0 -> 106423 bytes
venv1/Scripts/pip3.exe | Bin 0 -> 106423 bytes
venv1/Scripts/pymon.exe | Bin 0 -> 106411 bytes
venv1/Scripts/python.exe | Bin 0 -> 535056 bytes
venv1/Scripts/pythonw.exe | Bin 0 -> 534544 bytes
venv1/Scripts/watchmedo.exe | Bin 0 -> 106419 bytes
venv1/pyvenv.cfg | 3 +
32 files changed, 1197 insertions(+), 50 deletions(-)
create mode 100644 .gitignore
create mode 100644 user/UE-archi-distribuees-User-1.0.0.0.resolved.yaml
create mode 100644 user/templates/add_a_booking.html
create mode 100644 user/templates/booking_made.html
create mode 100644 user/templates/error_get_booking_per_user.html
create mode 100644 user/templates/get_movies_available_at_date.html
rename {movie => user}/templates/movies_per_ratings.html (100%)
create mode 100644 user/templates/response_add_booking.html
create mode 100644 venv1/Scripts/Activate.ps1
create mode 100644 venv1/Scripts/activate
create mode 100644 venv1/Scripts/activate.bat
create mode 100644 venv1/Scripts/deactivate.bat
create mode 100644 venv1/Scripts/easy_install-3.9.exe
create mode 100644 venv1/Scripts/easy_install.exe
create mode 100644 venv1/Scripts/flask.exe
create mode 100644 venv1/Scripts/normalizer.exe
create mode 100644 venv1/Scripts/pip.exe
create mode 100644 venv1/Scripts/pip3.9.exe
create mode 100644 venv1/Scripts/pip3.exe
create mode 100644 venv1/Scripts/pymon.exe
create mode 100644 venv1/Scripts/python.exe
create mode 100644 venv1/Scripts/pythonw.exe
create mode 100644 venv1/Scripts/watchmedo.exe
create mode 100644 venv1/pyvenv.cfg
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..a683905
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,179 @@
+# Created by https://www.toptal.com/developers/gitignore/api/python
+# Edit at https://www.toptal.com/developers/gitignore?templates=python
+
+### Python ###
+# Byte-compiled / optimized / DLL files
+__pycache__/
+*.py[cod]
+*$py.class
+
+# C extensions
+*.so
+
+# venv
+.venv1
+
+# Distribution / packaging
+.Python
+build/
+develop-eggs/
+dist/
+downloads/
+eggs/
+.eggs/
+lib/
+lib64/
+parts/
+sdist/
+var/
+wheels/
+share/python-wheels/
+*.egg-info/
+.installed.cfg
+*.egg
+MANIFEST
+
+# PyInstaller
+# Usually these files are written by a python script from a template
+# before PyInstaller builds the exe, so as to inject date/other infos into it.
+*.manifest
+*.spec
+
+# Installer logs
+pip-log.txt
+pip-delete-this-directory.txt
+
+# Unit test / coverage reports
+htmlcov/
+.tox/
+.nox/
+.coverage
+.coverage.*
+.cache
+nosetests.xml
+coverage.xml
+*.cover
+*.py,cover
+.hypothesis/
+.pytest_cache/
+cover/
+
+# Translations
+*.mo
+*.pot
+
+# Django stuff:
+*.log
+local_settings.py
+db.sqlite3
+db.sqlite3-journal
+
+# Flask stuff:
+instance/
+.webassets-cache
+
+# Scrapy stuff:
+.scrapy
+
+# Sphinx documentation
+docs/_build/
+
+# PyBuilder
+.pybuilder/
+target/
+
+# Jupyter Notebook
+.ipynb_checkpoints
+
+# IPython
+profile_default/
+ipython_config.py
+
+# pyenv
+# For a library or package, you might want to ignore these files since the code is
+# intended to run in multiple environments; otherwise, check them in:
+# .python-version
+
+# pipenv
+# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
+# However, in case of collaboration, if having platform-specific dependencies or dependencies
+# having no cross-platform support, pipenv may install dependencies that don't work, or not
+# install all needed dependencies.
+#Pipfile.lock
+
+# poetry
+# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
+# This is especially recommended for binary packages to ensure reproducibility, and is more
+# commonly ignored for libraries.
+# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
+#poetry.lock
+
+# pdm
+# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
+#pdm.lock
+# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
+# in version control.
+# https://pdm.fming.dev/#use-with-ide
+.pdm.toml
+
+# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
+__pypackages__/
+
+# Celery stuff
+celerybeat-schedule
+celerybeat.pid
+
+# SageMath parsed files
+*.sage.py
+
+# Environments
+.env
+.venv
+env/
+venv/
+ENV/
+env.bak/
+venv.bak/
+
+# Spyder project settings
+.spyderproject
+.spyproject
+
+# Rope project settings
+.ropeproject
+
+# mkdocs documentation
+/site
+
+# mypy
+.mypy_cache/
+.dmypy.json
+dmypy.json
+
+# Pyre type checker
+.pyre/
+
+# pytype static type analyzer
+.pytype/
+
+# Cython debug symbols
+cython_debug/
+
+# PyCharm
+# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
+# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
+# and can be added to the global gitignore or merged into this file. For a more nuclear
+# option (not recommended) you can uncomment the following to ignore the entire idea folder.
+#.idea/
+
+### Python Patch ###
+# Poetry local configuration file - https://python-poetry.org/docs/configuration/#local-configuration
+poetry.toml
+
+# ruff
+.ruff_cache/
+
+# LSP config files
+pyrightconfig.json
+
+# End of https://www.toptal.com/developers/gitignore/api/python
\ No newline at end of file
diff --git a/booking/UE-archi-distribuees-Booking-1.0.0-resolved.yaml b/booking/UE-archi-distribuees-Booking-1.0.0-resolved.yaml
index bae0c98..cc1e86a 100644
--- a/booking/UE-archi-distribuees-Booking-1.0.0-resolved.yaml
+++ b/booking/UE-archi-distribuees-Booking-1.0.0-resolved.yaml
@@ -105,6 +105,31 @@ paths:
description: 'Wrong input"'
"409":
description: an existing item already exists
+ /movies_at_the_date/{date}:
+ get:
+ tags:
+ - admins
+ - developers
+ summary: get all the bookings available at the date date
+ description: Contact the API Times to get all the bookings available at the date date
+ operationId: get_movie_at_date
+ parameters:
+ - name: date
+ in: path
+ description: date of the booking
+ required: true
+ style: simple
+ schema:
+ type: string
+ responses:
+ "200":
+ description: Boonkings returned
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Schedule'
+ "400":
+ description: There was a problem with the request
components:
schemas:
AllBookings:
@@ -150,3 +175,17 @@ components:
movieid:
type: string
example: 276c79ec-a26a-40a6-b3d3-fb242a5947b6
+ Schedule:
+ required:
+ - date
+ - movies
+ type: object
+ properties:
+ date:
+ type: string
+ example: "20151130"
+ movies:
+ type: array
+ items:
+ type: string
+ example: 720d006c-3a57-4b6a-b18f-9b713b073f3c
diff --git a/booking/booking.py b/booking/booking.py
index 7574186..aea32ff 100644
--- a/booking/booking.py
+++ b/booking/booking.py
@@ -7,46 +7,49 @@
PORT = 3201
HOST = '0.0.0.0'
+PATH_TIMES:str = "http://localhost:3202"
with open('{}/databases/bookings.json'.format("."), "r") as jsf:
bookings = json.load(jsf)["bookings"]
-with open("C:/ProgramData/Projets/ue-CONT/TP1/UE-AD-A1-REST/showtime/databases/times.json".format("."), "r") as jsf:
- schedule = json.load(jsf)["schedule"]
-
-# We define a list of all the dates available in the schedule :
-dates = []
-for show in schedule :
- dates.append(str(show["date"]))
-print(dates)
-
@app.route("/", methods=['GET'])
def home():
- return "Welcome to the Booking service!
"
+ """This function return the homepage of the API booking"""
+ return make_response("Welcome to the Booking service!
",200)
@app.route("/bookings",methods=["GET"])
def get_json():
"""This function return all the movie's reservations"""
- return make_response(jsonify(bookings))
+ return make_response(jsonify(bookings),200)
@app.route("/bookings/",methods=["GET"])
def get_booking_for_user(userid:str):
"""This function get all the bookings made by the user user_id """
for reservation in bookings:
if userid == reservation["userid"]: # We found the good user
- return make_response(jsonify(reservation["dates"]),200)
+ return make_response({"dates":reservation["dates"],"userid":userid},200)
# We didn't find the user so we return an error
return make_response(jsonify({"error": "bad input parameter"}),400)
@app.route("/bookings/",methods=["POST"])
def add_booking_byuser(userid:str):
- """This function get all the bookings made by the user user_id """
+ """This function adds a booking at the bookings made by the user user_id"""
# We check if the user gave a new movie
+
if request.args:
req = request.args
+ # Firstly we check if the movie is available at the date req["date"]
+ # We get the movies wich will be projected at the date req["date"]
+ movies_available_response = requests.request('GET', PATH_TIMES + "/showmovies" + "/" + req["date"] )
+ # The date doesn't exist
+ if movies_available_response.status_code == 400:
+ return make_response(jsonify({"error": "bad input parameter"}),201)
+ else:
+ # The movie ins't projected
+ if req["movieid"] not in movies_available_response.json()["movies"]:
+ return make_response(jsonify({"error": "bad input parameter"}),201)
for reservation in bookings:
if userid == reservation["userid"]: # We found the good user
- if req["date"] in dates : # Check if there are movies shown during that date
for date in reservation["dates"]:
if date["date"] == req["date"] :
# We need to check if the user didn't already book this movie
@@ -57,25 +60,46 @@ def add_booking_byuser(userid:str):
date["movies"].append(req["movieid"])
# We write in the database
write(bookings)
- res = make_response(jsonify({"message":"Booking added"}),200)
+
+ res = make_response({"userid":userid,"dates": date["movies"]},200) # We return the bookings of the day we add a booking
return res
#It is a new date
reservation["dates"].append({"date":req["date"],"movies":[req["movieid"]]})
# We write in the database
write(bookings)
- res = make_response(jsonify({"message":"Booking created"}),200)
+ # We return the bookings of the day we add a booking
+ res = make_response({"userid":userid,"dates":[{"date":req["date"],"movies":[req["movieid"]]}]},200)
return res
- else :
- return make_response(jsonify({"error": "bad input : date is unavailable"}),202)
- # We didn't find the user so we return an error
- return make_response(jsonify({"error": "bad input parameter"}),201)
+ # We didn't find the user so we need to add this user to our database
+ bookings.append({
+ "userid":userid,
+ "dates": [{
+ "date":req["date"],
+ "movies":[req["movieid"]]
+ }]
+ })
+ # We write in the database
+ write(bookings)
+ return make_response({"userid":userid,"dates":[{"date":req["date"],"movies":[req["movieid"]]}]},200)
return make_response(jsonify({"error": "Wrong input"}),400)
-def write(movies):
+@app.route("/movies_at_the_date/",methods=["GET"])
+def get_movie_at_date(date:str):
+ """This function will get all the movies available at the date date"""
+ # We ask the microservice times the movies available at date
+ req = requests.request("GET", PATH_TIMES + f"/showmovies/{date}")
+ if req.status_code == 200:
+ # We have gotten the id of the movies
+ return make_response(req.json(),200)
+ # The request failed
+ return make_response({"error":"There was a problem with the request"},400)
+
+def write(book):
with open('{}/databases/bookings.json'.format("."), 'w') as f:
- json.dump({"movies" : movies}, f)
+ json.dump({"bookings" : book}, f)
+
if __name__ == "__main__":
print("Server running in port %s"%(PORT))
app.run(host=HOST, port=PORT)
diff --git a/booking/databases/bookings.json b/booking/databases/bookings.json
index f596925..0d54ca6 100644
--- a/booking/databases/bookings.json
+++ b/booking/databases/bookings.json
@@ -8,6 +8,12 @@
"movies": [
"267eedb8-0f5d-42d5-8f43-72426b9fb3e6"
]
+ },
+ {
+ "date": "20151130",
+ "movies": [
+ "720d006c-3a57-4b6a-b18f-9b713b073f3c"
+ ]
}
]
},
@@ -25,6 +31,12 @@
"movies": [
"276c79ec-a26a-40a6-b3d3-fb242a5947b6"
]
+ },
+ {
+ "date": "20151130",
+ "movies": [
+ "720d006c-3a57-4b6a-b18f-9b713b073f3c"
+ ]
}
]
},
@@ -42,17 +54,21 @@
"date": "20151205",
"movies": [
"a8034f44-aee4-44cf-b32c-74cf452aaaae",
- "276c79ec-a26a-40a6-b3d3-fb242a5947b6",
- "276c79ec-a26a-40a6-b3d3-fb242a5947b8"
+ "276c79ec-a26a-40a6-b3d3-fb242a5947b6"
]
- },
+ }
+ ]
+ },
+ {
+ "userid": "peter_curley",
+ "dates": [
{
- "date": "20151210",
+ "date": "20151130",
"movies": [
- "276c79ec-a26a-40a6-b3d3-fb242a5947b6"
+ "720d006c-3a57-4b6a-b18f-9b713b073f3c"
]
}
]
}
]
-}
+}
\ No newline at end of file
diff --git a/movie/UE-archi-distribuees-Movie-1.0.0-resolved.yaml b/movie/UE-archi-distribuees-Movie-1.0.0-resolved.yaml
index f3517b9..6d26e78 100644
--- a/movie/UE-archi-distribuees-Movie-1.0.0-resolved.yaml
+++ b/movie/UE-archi-distribuees-Movie-1.0.0-resolved.yaml
@@ -198,7 +198,11 @@ paths:
operationId: get_movies_classify_per_ratings
responses:
"200":
- description: return a HTML page
+ description: Return a MovieList
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/MovieList'
/directors:
get:
tags:
@@ -208,7 +212,11 @@ paths:
operationId: get_directors
responses:
"200":
- description: return a HTML page
+ description: return an object
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/DirectorList'
/directors/{movie_id}{director_name}:
put:
tags:
@@ -270,5 +278,20 @@ components:
id:
type: string
example: 39ab85e5-5e8e-4dc5-afea-65dc368bd7ab
+ MovieList:
+ required:
+ - list_movies_sorted
+ properties:
+ list_movies_sorted:
+ type: array
+ example: [[7.8,"Peter Pan"],[4.1,"Spider man : Across the spidervers"]]
+ DirectorList:
+ required:
+ - list_directors
+ properties:
+ list_directors:
+ type: array
+ example: ["James Gun", "Steven Spielberg"]
+
diff --git a/movie/databases/movies.json b/movie/databases/movies.json
index 5584a0c..43ae81b 100644
--- a/movie/databases/movies.json
+++ b/movie/databases/movies.json
@@ -1 +1,52 @@
-{"movies": [{"title": "The Good Dinosaur", "rating": 7.4, "director": "Peter Sohn", "id": "720d006c-3a57-4b6a-b18f-9b713b073f3c"}, {"title": "The Martian", "rating": 8.2, "director": "Ridley Scott", "id": "a8034f44-aee4-44cf-b32c-74cf452aaaae"}, {"title": "The Night Before", "rating": 7.4, "director": "Jonathan Levine", "id": "96798c08-d19b-4986-a05d-7da856efb697"}, {"title": "Creed", "rating": 8.8, "director": "Ryan Coogler", "id": "267eedb8-0f5d-42d5-8f43-72426b9fb3e6"}, {"title": "Victor Frankenstein", "rating": 6.4, "director": "Paul McGuigan", "id": "7daf7208-be4d-4944-a3ae-c1c2f516f3e6"}, {"title": "The Danish Girl", "rating": 5.3, "director": "Tom Hooper", "id": "276c79ec-a26a-40a6-b3d3-fb242a5947b6"}, {"title": "Spectre", "rating": 7.1, "director": "Sam Mendes", "id": "39ab85e5-5e8e-4dc5-afea-65dc368bd7ab"}, {"title": "Test", "rating": 1.2, "director": "Someone", "id": "xxx"}, {"title": "Guardians of the Galaxy", "rating": 1.2, "director": "James Gun", "id": "7cv89fs5-7845-2sc3-6942-cdf4qz5rz"}, {"title": "Goo", "rating": 1.2, "director": "gooooooooo", "id": "7cv89fs5-7845-2sc3-6942-cds4qz5rz"}]}
\ No newline at end of file
+{
+ "movies": [
+ {
+ "title": "The Good Dinosaur",
+ "rating": 7.4,
+ "director": "Peter Sohn",
+ "id": "720d006c-3a57-4b6a-b18f-9b713b073f3c"
+ },
+ {
+ "title": "The Martian",
+ "rating": 8.2,
+ "director": "Ridley Scott",
+ "id": "a8034f44-aee4-44cf-b32c-74cf452aaaae"
+ },
+ {
+ "title": "The Night Before",
+ "rating": 7.4,
+ "director": "Jonathan Levine",
+ "id": "96798c08-d19b-4986-a05d-7da856efb697"
+ },
+ {
+ "title": "Creed",
+ "rating": 8.8,
+ "director": "Ryan Coogler",
+ "id": "267eedb8-0f5d-42d5-8f43-72426b9fb3e6"
+ },
+ {
+ "title": "Victor Frankenstein",
+ "rating": 6.4,
+ "director": "Paul McGuigan",
+ "id": "7daf7208-be4d-4944-a3ae-c1c2f516f3e6"
+ },
+ {
+ "title": "The Danish Girl",
+ "rating": 5.3,
+ "director": "Tom Hooper",
+ "id": "276c79ec-a26a-40a6-b3d3-fb242a5947b6"
+ },
+ {
+ "title": "Spectre",
+ "rating": 7.1,
+ "director": "Sam Mendes",
+ "id": "39ab85e5-5e8e-4dc5-afea-65dc368bd7ab"
+ },
+ {
+ "title": "Test",
+ "rating": 1.2,
+ "director": "Someone",
+ "id": "xxx"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/movie/movie.py b/movie/movie.py
index f255735..50cce74 100644
--- a/movie/movie.py
+++ b/movie/movie.py
@@ -36,6 +36,7 @@ def get_movie_byid(movieid):
@app.route("/moviesbytitle", methods=['GET'])
def get_movie_bytitle():
json = ""
+ print("request.args : ", request.args)
if request.args:
req = request.args
for movie in movies:
@@ -116,12 +117,8 @@ def get_movies_classify_per_ratings():
# We get the list of movies associated with there ranking
for movie in movies:
list_movies.append([movie["rating"],movie["title"]])
- list_movies.sort()
- body_text = ""
- # We format the text to create a list in the html screen
- for elem in list_movies:
- body_text += f"{elem[1]} : {elem[0]} \n"
- return make_response(render_template('movies_per_ratings.html', body_text=body_text),200)
+ list_movies.sort(reverse=True)
+ return make_response({"list_movies_sorted":list_movies},200)
@app.route("/directors",methods=["GET"])
def get_all_directors():
@@ -141,6 +138,15 @@ def update_director_movie(director_name:str,movie_id:str):
return res
return make_response(jsonify({"error":"movie ID not found"}),201)
+@app.route("/movieid_linked_movietitle")
+def get_movieid_linked_movie_title():
+ """This function links the title of the movie and its id"""
+ dict_movie = {}
+ # We read the whole database and we link the name of the movie with its id
+ for movie in movies:
+ dict_movie[movie["id"]] = movie["title"]
+ return make_response(dict_movie,200)
+
if __name__ == "__main__":
#p = sys.argv[1]
print("Server running in port %s"%(PORT))
diff --git a/showtime/showtime.py b/showtime/showtime.py
index 700d137..6834828 100644
--- a/showtime/showtime.py
+++ b/showtime/showtime.py
@@ -12,18 +12,18 @@
@app.route("/", methods=['GET'])
def home():
- return "Welcome to the Showtime service!
"
+ return make_response("Welcome to the Showtime service!
",200)
# Fonction pour retourner toute la base de données times : La liste des
# dates avec les films qui seraient projetés
@app.route("/showtimes", methods=['GET'])
-def get_showtimes():
- result = make_response(jsonify(schedule),200)
+def get_schedule():
+ result = make_response({"schedule":schedule},200)
return result
# Fonction pour retourner la liste des films projetés pour une date donnée
@app.route("/showmovies/", methods=['GET'])
-def get_schedule_bydate(date):
+def get_movies_bydate(date):
for showtime in schedule:
if str(showtime["date"]) == str(date):
result = make_response(jsonify(showtime),200)
diff --git a/user/UE-archi-distribuees-User-1.0.0.0.resolved.yaml b/user/UE-archi-distribuees-User-1.0.0.0.resolved.yaml
new file mode 100644
index 0000000..85e99cf
--- /dev/null
+++ b/user/UE-archi-distribuees-User-1.0.0.0.resolved.yaml
@@ -0,0 +1,171 @@
+openapi: 3.0.1
+info:
+ title: User API
+ version: 1.0.0
+ description: API made to manage the request by the user
+ contact:
+ email: gabriel.bocquet@imt-atlantique.fr
+ license:
+ name: GPL v3
+ url: https://www.gnu.org/licenses/gpl-3.0.en.html
+tags:
+- name: admins
+ description: Secured Admin-only calls
+- name: developers
+ description: Operations available to regular developers
+paths:
+ /:
+ get:
+ summary: Home page
+ tags:
+ - developers
+ description: Return a welome message
+ responses:
+ '200':
+ description: Welcome page
+ content:
+ text/html:
+ schema:
+ type: string
+ example: "Welcome to the User service!
"
+ /movies_per_ratings:
+ get:
+ summary: return the movies sorted by decreasing rate
+ description: Get and return all the movies, sorted by decreasing rate
+ responses:
+ '200':
+ description: Html page which prints the movies sorted by decreasing rate
+ content:
+ text/html:
+ schema:
+ type: string
+ example: ""
+ '400':
+ description: There was a problem during the request.
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ /movies_available/{date}:
+ get:
+ summary: Get the moveis at the specified date
+ description: Print all the movies which can be booked at the date date
+ parameters:
+ - in: path
+ name: date
+ required: true
+ explode: false
+ style: simple
+ schema:
+ type: string
+ description: Date YYYYMMDD
+ responses:
+ '200':
+ description: HTML page which shows the movies available at the date date
+ content:
+ text/html:
+ schema:
+ type: string
+ example: ""
+ '400':
+ description: There was a problem during the request
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ /book_a_movie:
+ post:
+ summary: Book a movie
+ description: Book a movie for the user at the specified date
+ requestBody:
+ description: Informations needed
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/BookingRequest'
+ responses:
+ '200':
+ description: Booking successful
+ content:
+ text/html:
+ schema:
+ type: string
+ example: "Example
"
+ '205':
+ description: Impossible to book the movie
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ example:
+ message: "We couldn't book the date, Sadge :'("
+ '400':
+ description: Bad argument
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+ /booking_made/{username}:
+ get:
+ summary: Get the bookings made by the user
+ description: Get the bookings made by the user
+ parameters:
+ - in: path
+ name: username
+ required: true
+ schema:
+ type: string
+ description: Name of the user
+ responses:
+ '200':
+ description: HTML page which shows the bookings made by the user
+ content:
+ text/html:
+ schema:
+ type: string
+ example: ""
+ '300':
+ description: The user name doesn't exist
+ content:
+ text/html:
+ schema:
+ type: string
+ example: "The user john_doe doesn't exist
"
+ '301':
+ description: The user exists but have zero booking
+ content:
+ text/html:
+ schema:
+ type: string
+ example: "Zero booking was made with the user john_doe
"
+components:
+ schemas:
+ BookingRequest:
+ type: object
+ required:
+ - moviename
+ - date
+ - username
+ properties:
+ moviename:
+ type: string
+ description: Name of the movie which have to be booked.
+ example: Beetlejuice
+ date:
+ type: string
+ description: Date of the booking wanted YYYYMMDD.
+ example: "20240430"
+ username:
+ type: string
+ description: Name of the user who wants to book the movie
+ example: "john_doe"
+ Error:
+ type: object
+ required:
+ - error
+ properties:
+ error:
+ type: string
+ description: Error Message
+ example: "Bad argument"
diff --git a/user/templates/add_a_booking.html b/user/templates/add_a_booking.html
new file mode 100644
index 0000000..2c14e90
--- /dev/null
+++ b/user/templates/add_a_booking.html
@@ -0,0 +1,11 @@
+
+
+
+
+ Movies booked
+
+
+ The user {{username}} succeded to book: {{body_text}}
+
+
+
\ No newline at end of file
diff --git a/user/templates/booking_made.html b/user/templates/booking_made.html
new file mode 100644
index 0000000..d399cea
--- /dev/null
+++ b/user/templates/booking_made.html
@@ -0,0 +1,14 @@
+
+
+
+
+ Movies booked by the user
+
+
+ The user {{username}} booked :
+
+
{{ body_text | safe}}
+
+
+
+
\ No newline at end of file
diff --git a/user/templates/error_get_booking_per_user.html b/user/templates/error_get_booking_per_user.html
new file mode 100644
index 0000000..3b74206
--- /dev/null
+++ b/user/templates/error_get_booking_per_user.html
@@ -0,0 +1,10 @@
+
+
+
+
+ Movies available
+
+
+ Sorry...😢 Error {{error}} : {{body_text}}
+
+
\ No newline at end of file
diff --git a/user/templates/get_movies_available_at_date.html b/user/templates/get_movies_available_at_date.html
new file mode 100644
index 0000000..38cb8d1
--- /dev/null
+++ b/user/templates/get_movies_available_at_date.html
@@ -0,0 +1,14 @@
+
+
+
+
+ Movies available
+
+
+ The ⌚ {{date}} , these movies are availables :
+
+
+
+
+
+
\ No newline at end of file
diff --git a/movie/templates/movies_per_ratings.html b/user/templates/movies_per_ratings.html
similarity index 100%
rename from movie/templates/movies_per_ratings.html
rename to user/templates/movies_per_ratings.html
diff --git a/user/templates/response_add_booking.html b/user/templates/response_add_booking.html
new file mode 100644
index 0000000..19901d0
--- /dev/null
+++ b/user/templates/response_add_booking.html
@@ -0,0 +1,12 @@
+
+
+
+ Ranking of the best movies
+
+
+
+
✅ The booking {{body_text}} was added !
+
+
+
+
\ No newline at end of file
diff --git a/user/user.py b/user/user.py
index df49538..f5c8c84 100644
--- a/user/user.py
+++ b/user/user.py
@@ -20,22 +20,91 @@ def home():
@app.route("/movies_per_ratings",methods=["GET"])
def get_movies_per_ratings():
"""This function will get all the movies available sorted by rating"""
- return requests.request("GET", MOVIE_PATH +"/movies_per_ratings")
+ req = requests.request("GET", MOVIE_PATH +"/movies_per_ratings")
+ if req.status_code == 200:
+ list_movies = req.json()["list_movies_sorted"]
+ # We format the text to create a list in the html screen
+ body_text = ""
+ for elem in list_movies:
+ body_text += f"{elem[1]} : {elem[0]} \n" #elem[1] = movie_name & elem[2] = rating
+ return make_response(render_template('movies_per_ratings.html', body_text=body_text),200)
+ # The request failed
+ return make_response({"error": "There was a problem during the request"},400)
@app.route("/movies_available/",methods=["GET"])
def get_movies_available_at_date(date:str):
- """This function shows what are the movies available at the date date"""
- pass
+ """This function shows what are the movies (their name) available at the date date"""
+ # We get the ids of the movies available
+ req = requests.request("GET", BOOKING_PATH + f"/movies_at_the_date/{date}")
+ if req.status_code==200:
+ # Now we get all the dict which link the movie id with their title
+ req2 = requests.request("GET", MOVIE_PATH + "/movieid_linked_movietitle")
+ if req2.status_code == 200:
+ list_name = []
+ dict_id_title = req2.json() # With this dict, we can convert an id into a title
+ for movieid in req.json()["movies"]:
+ list_name.append(dict_id_title[movieid])
+ body_text = ""
+ for elem in list_name:
+ body_text += f"{elem} \n" #elem[1] = movie_name & elem[2] = rating
+ return make_response(render_template('get_movies_available_at_date.html',body_text=body_text,date=f"{date[0:4]}/{date[4:6]}/{date[6:]}"))
+ return make_response({"error":"There was a problem during the request"},400)
+
+ return make_response({"error":"There was a problem during the request"},400)
-@app.route("/book_a_movie//")
-def book_the_movie(moviename:str,username:str):
- """This function books the movie name moviename for the user username"""
- pass
+@app.route("/book_a_movie",methods=["POST"])
+def book_the_movie(): # Convertir ceci en POST avec dico
+ ## TO DO : Voir si ça marche si l'utilisateur n'est pas dans la base de données initialisement
+ if request.args:
+ """This function books the movie name moviename for the user username"""
+ # We get the informations we want
+ request_json = request.get_json()
+ moviename, date, username = request_json["moviename"], request_json["date"],request_json["username"]
+ # We need to convert the moviename into a movie_id
+ req = requests.request("GET", MOVIE_PATH + "/movieid_linked_movietitle")
+ if req.status_code == 200:
+ dict_id_to_name = req.json()
+ # We seek the id corresponding to the title moviename
+ for key in dict_id_to_name.keys():
+ if moviename == dict_id_to_name[key]:
+ # The id of the movie is key
+ new_movie = {"date":date,"movieid":key}
+ req2 = requests.request("POST",BOOKING_PATH + f"/bookings/{convert_username_id(username)}",
+ params=new_movie)
+ if req2.status_code==200:
+ return make_response(render_template('booking_made.html',bodytext=moviename,username=username),200)
+ else:
+ return make_response({"message":"We couldn't book the date, Sadge :'("},205)
+ return make_response({"error": "Bad argument"},400)
+ return make_response({"error":"Bad argument"},400)
-@app.route("/booking_made/",methods=["GET"])
+@app.route("/booking_made/",methods=["GET"]) # TO DO : ajouter l'utilisateur au lieu de lever une erreur ???
def get_booking_made(username:str):
"""This function will get all the booking already made by username"""
- return requests.request("GET", BOOKING_PATH + "/bookings/" + convert_username_id(username))
+ # We check if the user is register in the user database
+ for user_registered in users:
+ if user_registered["name"] == username:
+ print("username : ", username)
+ # The user is in the database
+ # We ask the api booking to give us all the booking of username
+ req = requests.request("GET", BOOKING_PATH + "/bookings/" + convert_username_id(username)) #list_json
+ if req.status_code==200:
+ if len(req.json()["dates"]) > 0:
+ # The user made reservations
+ # We get the dict which allow us to convert the id into a movie title
+ req2 = requests.request("GET", MOVIE_PATH + "/movieid_linked_movietitle") # return a list
+ if req2.status_code == 200:
+ dict_id_to_name = req2.json()
+ body_text = ""
+ for elem in req.json()["dates"]:
+ body_text+= f" The {elem['date'][0:4]}/{elem['date'][4:6]}/{elem['date'][6:]}: \n"
+ for movieid in elem["movies"]:
+ body_text += "- "+dict_id_to_name[movieid] + "
\n"
+ body_text += "
\n"
+ return make_response(render_template('booking_made.html',body_text=body_text,username=username))
+ # If we are here, it means that the user didn't book any movies
+ return make_response(render_template('error_get_booking_per_user.html',body_text=f"Zero booking was made with the user {username}",error="301"),301)
+ return make_response(render_template('error_get_booking_per_user.html',body_text=f"The user {username} doesn't exist",error="300"),300)
def convert_username_id(username:str):
"""This get the id corresponding to the user username"""
@@ -43,6 +112,7 @@ def convert_username_id(username:str):
if user["name"]==username:
return user["id"]
+
if __name__ == "__main__":
print("Server running in port %s"%(PORT))
app.run(host=HOST, port=PORT)
diff --git a/venv1/Scripts/Activate.ps1 b/venv1/Scripts/Activate.ps1
new file mode 100644
index 0000000..953fd89
--- /dev/null
+++ b/venv1/Scripts/Activate.ps1
@@ -0,0 +1,384 @@
+<#
+.Synopsis
+Activate a Python virtual environment for the current PowerShell session.
+
+.Description
+Pushes the python executable for a virtual environment to the front of the
+$Env:PATH environment variable and sets the prompt to signify that you are
+in a Python virtual environment. Makes use of the command line switches as
+well as the `pyvenv.cfg` file values present in the virtual environment.
+
+.Parameter VenvDir
+Path to the directory that contains the virtual environment to activate. The
+default value for this is the parent of the directory that the Activate.ps1
+script is located within.
+
+.Parameter Prompt
+The prompt prefix to display when this virtual environment is activated. By
+default, this prompt is the name of the virtual environment folder (VenvDir)
+surrounded by parentheses and followed by a single space (ie. '(.venv) ').
+
+.Example
+Activate.ps1
+Activates the Python virtual environment that contains the Activate.ps1 script.
+
+.Example
+Activate.ps1 -Verbose
+Activates the Python virtual environment that contains the Activate.ps1 script,
+and shows extra information about the activation as it executes.
+
+.Example
+Activate.ps1 -VenvDir C:\Users\MyUser\Common\.venv
+Activates the Python virtual environment located in the specified location.
+
+.Example
+Activate.ps1 -Prompt "MyPython"
+Activates the Python virtual environment that contains the Activate.ps1 script,
+and prefixes the current prompt with the specified string (surrounded in
+parentheses) while the virtual environment is active.
+
+.Notes
+On Windows, it may be required to enable this Activate.ps1 script by setting the
+execution policy for the user. You can do this by issuing the following PowerShell
+command:
+
+PS C:\> Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser
+
+For more information on Execution Policies:
+https://go.microsoft.com/fwlink/?LinkID=135170
+
+#>
+Param(
+ [Parameter(Mandatory = $false)]
+ [String]
+ $VenvDir,
+ [Parameter(Mandatory = $false)]
+ [String]
+ $Prompt
+)
+
+<# Function declarations --------------------------------------------------- #>
+
+<#
+.Synopsis
+Remove all shell session elements added by the Activate script, including the
+addition of the virtual environment's Python executable from the beginning of
+the PATH variable.
+
+.Parameter NonDestructive
+If present, do not remove this function from the global namespace for the
+session.
+
+#>
+function global:deactivate ([switch]$NonDestructive) {
+ # Revert to original values
+
+ # The prior prompt:
+ if (Test-Path -Path Function:_OLD_VIRTUAL_PROMPT) {
+ Copy-Item -Path Function:_OLD_VIRTUAL_PROMPT -Destination Function:prompt
+ Remove-Item -Path Function:_OLD_VIRTUAL_PROMPT
+ }
+
+ # The prior PYTHONHOME:
+ if (Test-Path -Path Env:_OLD_VIRTUAL_PYTHONHOME) {
+ Copy-Item -Path Env:_OLD_VIRTUAL_PYTHONHOME -Destination Env:PYTHONHOME
+ Remove-Item -Path Env:_OLD_VIRTUAL_PYTHONHOME
+ }
+
+ # The prior PATH:
+ if (Test-Path -Path Env:_OLD_VIRTUAL_PATH) {
+ Copy-Item -Path Env:_OLD_VIRTUAL_PATH -Destination Env:PATH
+ Remove-Item -Path Env:_OLD_VIRTUAL_PATH
+ }
+
+ # Just remove the VIRTUAL_ENV altogether:
+ if (Test-Path -Path Env:VIRTUAL_ENV) {
+ Remove-Item -Path env:VIRTUAL_ENV
+ }
+
+ # Just remove the _PYTHON_VENV_PROMPT_PREFIX altogether:
+ if (Get-Variable -Name "_PYTHON_VENV_PROMPT_PREFIX" -ErrorAction SilentlyContinue) {
+ Remove-Variable -Name _PYTHON_VENV_PROMPT_PREFIX -Scope Global -Force
+ }
+
+ # Leave deactivate function in the global namespace if requested:
+ if (-not $NonDestructive) {
+ Remove-Item -Path function:deactivate
+ }
+}
+
+<#
+.Description
+Get-PyVenvConfig parses the values from the pyvenv.cfg file located in the
+given folder, and returns them in a map.
+
+For each line in the pyvenv.cfg file, if that line can be parsed into exactly
+two strings separated by `=` (with any amount of whitespace surrounding the =)
+then it is considered a `key = value` line. The left hand string is the key,
+the right hand is the value.
+
+If the value starts with a `'` or a `"` then the first and last character is
+stripped from the value before being captured.
+
+.Parameter ConfigDir
+Path to the directory that contains the `pyvenv.cfg` file.
+#>
+function Get-PyVenvConfig(
+ [String]
+ $ConfigDir
+) {
+ Write-Verbose "Given ConfigDir=$ConfigDir, obtain values in pyvenv.cfg"
+
+ # Ensure the file exists, and issue a warning if it doesn't (but still allow the function to continue).
+ $pyvenvConfigPath = Join-Path -Resolve -Path $ConfigDir -ChildPath 'pyvenv.cfg' -ErrorAction Continue
+
+ # An empty map will be returned if no config file is found.
+ $pyvenvConfig = @{ }
+
+ if ($pyvenvConfigPath) {
+
+ Write-Verbose "File exists, parse `key = value` lines"
+ $pyvenvConfigContent = Get-Content -Path $pyvenvConfigPath
+
+ $pyvenvConfigContent | ForEach-Object {
+ $keyval = $PSItem -split "\s*=\s*", 2
+ if ($keyval[0] -and $keyval[1]) {
+ $val = $keyval[1]
+
+ # Remove extraneous quotations around a string value.
+ if ("'""".Contains($val.Substring(0, 1))) {
+ $val = $val.Substring(1, $val.Length - 2)
+ }
+
+ $pyvenvConfig[$keyval[0]] = $val
+ Write-Verbose "Adding Key: '$($keyval[0])'='$val'"
+ }
+ }
+ }
+ return $pyvenvConfig
+}
+
+
+<# Begin Activate script --------------------------------------------------- #>
+
+# Determine the containing directory of this script
+$VenvExecPath = Split-Path -Parent $MyInvocation.MyCommand.Definition
+$VenvExecDir = Get-Item -Path $VenvExecPath
+
+Write-Verbose "Activation script is located in path: '$VenvExecPath'"
+Write-Verbose "VenvExecDir Fullname: '$($VenvExecDir.FullName)"
+Write-Verbose "VenvExecDir Name: '$($VenvExecDir.Name)"
+
+# Set values required in priority: CmdLine, ConfigFile, Default
+# First, get the location of the virtual environment, it might not be
+# VenvExecDir if specified on the command line.
+if ($VenvDir) {
+ Write-Verbose "VenvDir given as parameter, using '$VenvDir' to determine values"
+}
+else {
+ Write-Verbose "VenvDir not given as a parameter, using parent directory name as VenvDir."
+ $VenvDir = $VenvExecDir.Parent.FullName.TrimEnd("\\/")
+ Write-Verbose "VenvDir=$VenvDir"
+}
+
+# Next, read the `pyvenv.cfg` file to determine any required value such
+# as `prompt`.
+$pyvenvCfg = Get-PyVenvConfig -ConfigDir $VenvDir
+
+# Next, set the prompt from the command line, or the config file, or
+# just use the name of the virtual environment folder.
+if ($Prompt) {
+ Write-Verbose "Prompt specified as argument, using '$Prompt'"
+}
+else {
+ Write-Verbose "Prompt not specified as argument to script, checking pyvenv.cfg value"
+ if ($pyvenvCfg -and $pyvenvCfg['prompt']) {
+ Write-Verbose " Setting based on value in pyvenv.cfg='$($pyvenvCfg['prompt'])'"
+ $Prompt = $pyvenvCfg['prompt'];
+ }
+ else {
+ Write-Verbose " Setting prompt based on parent's directory's name. (Is the directory name passed to venv module when creating the virutal environment)"
+ Write-Verbose " Got leaf-name of $VenvDir='$(Split-Path -Path $venvDir -Leaf)'"
+ $Prompt = Split-Path -Path $venvDir -Leaf
+ }
+}
+
+Write-Verbose "Prompt = '$Prompt'"
+Write-Verbose "VenvDir='$VenvDir'"
+
+# Deactivate any currently active virtual environment, but leave the
+# deactivate function in place.
+deactivate -nondestructive
+
+# Now set the environment variable VIRTUAL_ENV, used by many tools to determine
+# that there is an activated venv.
+$env:VIRTUAL_ENV = $VenvDir
+
+if (-not $Env:VIRTUAL_ENV_DISABLE_PROMPT) {
+
+ Write-Verbose "Setting prompt to '$Prompt'"
+
+ # Set the prompt to include the env name
+ # Make sure _OLD_VIRTUAL_PROMPT is global
+ function global:_OLD_VIRTUAL_PROMPT { "" }
+ Copy-Item -Path function:prompt -Destination function:_OLD_VIRTUAL_PROMPT
+ New-Variable -Name _PYTHON_VENV_PROMPT_PREFIX -Description "Python virtual environment prompt prefix" -Scope Global -Option ReadOnly -Visibility Public -Value $Prompt
+
+ function global:prompt {
+ Write-Host -NoNewline -ForegroundColor Green "($_PYTHON_VENV_PROMPT_PREFIX) "
+ _OLD_VIRTUAL_PROMPT
+ }
+}
+
+# Clear PYTHONHOME
+if (Test-Path -Path Env:PYTHONHOME) {
+ Copy-Item -Path Env:PYTHONHOME -Destination Env:_OLD_VIRTUAL_PYTHONHOME
+ Remove-Item -Path Env:PYTHONHOME
+}
+
+# Add the venv to the PATH
+Copy-Item -Path Env:PATH -Destination Env:_OLD_VIRTUAL_PATH
+$Env:PATH = "$VenvExecDir$([System.IO.Path]::PathSeparator)$Env:PATH"
+
+# SIG # Begin signature block
+# MIIaHgYJKoZIhvcNAQcCoIIaDzCCGgsCAQExDzANBglghkgBZQMEAgEFADB5Bgor
+# BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG
+# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCAwnDYwEHaCQq0n
+# 8NAvsN7H7BO7/48rXCNwrg891FS5vaCCFBgwggPuMIIDV6ADAgECAhB+k+v7fMZO
+# WepLmnfUBvw7MA0GCSqGSIb3DQEBBQUAMIGLMQswCQYDVQQGEwJaQTEVMBMGA1UE
+# CBMMV2VzdGVybiBDYXBlMRQwEgYDVQQHEwtEdXJiYW52aWxsZTEPMA0GA1UEChMG
+# VGhhd3RlMR0wGwYDVQQLExRUaGF3dGUgQ2VydGlmaWNhdGlvbjEfMB0GA1UEAxMW
+# VGhhd3RlIFRpbWVzdGFtcGluZyBDQTAeFw0xMjEyMjEwMDAwMDBaFw0yMDEyMzAy
+# MzU5NTlaMF4xCzAJBgNVBAYTAlVTMR0wGwYDVQQKExRTeW1hbnRlYyBDb3Jwb3Jh
+# dGlvbjEwMC4GA1UEAxMnU3ltYW50ZWMgVGltZSBTdGFtcGluZyBTZXJ2aWNlcyBD
+# QSAtIEcyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsayzSVRLlxwS
+# CtgleZEiVypv3LgmxENza8K/LlBa+xTCdo5DASVDtKHiRfTot3vDdMwi17SUAAL3
+# Te2/tLdEJGvNX0U70UTOQxJzF4KLabQry5kerHIbJk1xH7Ex3ftRYQJTpqr1SSwF
+# eEWlL4nO55nn/oziVz89xpLcSvh7M+R5CvvwdYhBnP/FA1GZqtdsn5Nph2Upg4XC
+# YBTEyMk7FNrAgfAfDXTekiKryvf7dHwn5vdKG3+nw54trorqpuaqJxZ9YfeYcRG8
+# 4lChS+Vd+uUOpyyfqmUg09iW6Mh8pU5IRP8Z4kQHkgvXaISAXWp4ZEXNYEZ+VMET
+# fMV58cnBcQIDAQABo4H6MIH3MB0GA1UdDgQWBBRfmvVuXMzMdJrU3X3vP9vsTIAu
+# 3TAyBggrBgEFBQcBAQQmMCQwIgYIKwYBBQUHMAGGFmh0dHA6Ly9vY3NwLnRoYXd0
+# ZS5jb20wEgYDVR0TAQH/BAgwBgEB/wIBADA/BgNVHR8EODA2MDSgMqAwhi5odHRw
+# Oi8vY3JsLnRoYXd0ZS5jb20vVGhhd3RlVGltZXN0YW1waW5nQ0EuY3JsMBMGA1Ud
+# JQQMMAoGCCsGAQUFBwMIMA4GA1UdDwEB/wQEAwIBBjAoBgNVHREEITAfpB0wGzEZ
+# MBcGA1UEAxMQVGltZVN0YW1wLTIwNDgtMTANBgkqhkiG9w0BAQUFAAOBgQADCZuP
+# ee9/WTCq72i1+uMJHbtPggZdN1+mUp8WjeockglEbvVt61h8MOj5aY0jcwsSb0ep
+# rjkR+Cqxm7Aaw47rWZYArc4MTbLQMaYIXCp6/OJ6HVdMqGUY6XlAYiWWbsfHN2qD
+# IQiOQerd2Vc/HXdJhyoWBl6mOGoiEqNRGYN+tjCCBKMwggOLoAMCAQICEA7P9DjI
+# /r81bgTYapgbGlAwDQYJKoZIhvcNAQEFBQAwXjELMAkGA1UEBhMCVVMxHTAbBgNV
+# BAoTFFN5bWFudGVjIENvcnBvcmF0aW9uMTAwLgYDVQQDEydTeW1hbnRlYyBUaW1l
+# IFN0YW1waW5nIFNlcnZpY2VzIENBIC0gRzIwHhcNMTIxMDE4MDAwMDAwWhcNMjAx
+# MjI5MjM1OTU5WjBiMQswCQYDVQQGEwJVUzEdMBsGA1UEChMUU3ltYW50ZWMgQ29y
+# cG9yYXRpb24xNDAyBgNVBAMTK1N5bWFudGVjIFRpbWUgU3RhbXBpbmcgU2Vydmlj
+# ZXMgU2lnbmVyIC0gRzQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCi
+# Yws5RLi7I6dESbsO/6HwYQpTk7CY260sD0rFbv+GPFNVDxXOBD8r/amWltm+YXkL
+# W8lMhnbl4ENLIpXuwitDwZ/YaLSOQE/uhTi5EcUj8mRY8BUyb05Xoa6IpALXKh7N
+# S+HdY9UXiTJbsF6ZWqidKFAOF+6W22E7RVEdzxJWC5JH/Kuu9mY9R6xwcueS51/N
+# ELnEg2SUGb0lgOHo0iKl0LoCeqF3k1tlw+4XdLxBhircCEyMkoyRLZ53RB9o1qh0
+# d9sOWzKLVoszvdljyEmdOsXF6jML0vGjG/SLvtmzV4s73gSneiKyJK4ux3DFvk6D
+# Jgj7C72pT5kI4RAocqrNAgMBAAGjggFXMIIBUzAMBgNVHRMBAf8EAjAAMBYGA1Ud
+# JQEB/wQMMAoGCCsGAQUFBwMIMA4GA1UdDwEB/wQEAwIHgDBzBggrBgEFBQcBAQRn
+# MGUwKgYIKwYBBQUHMAGGHmh0dHA6Ly90cy1vY3NwLndzLnN5bWFudGVjLmNvbTA3
+# BggrBgEFBQcwAoYraHR0cDovL3RzLWFpYS53cy5zeW1hbnRlYy5jb20vdHNzLWNh
+# LWcyLmNlcjA8BgNVHR8ENTAzMDGgL6AthitodHRwOi8vdHMtY3JsLndzLnN5bWFu
+# dGVjLmNvbS90c3MtY2EtZzIuY3JsMCgGA1UdEQQhMB+kHTAbMRkwFwYDVQQDExBU
+# aW1lU3RhbXAtMjA0OC0yMB0GA1UdDgQWBBRGxmmjDkoUHtVM2lJjFz9eNrwN5jAf
+# BgNVHSMEGDAWgBRfmvVuXMzMdJrU3X3vP9vsTIAu3TANBgkqhkiG9w0BAQUFAAOC
+# AQEAeDu0kSoATPCPYjA3eKOEJwdvGLLeJdyg1JQDqoZOJZ+aQAMc3c7jecshaAba
+# tjK0bb/0LCZjM+RJZG0N5sNnDvcFpDVsfIkWxumy37Lp3SDGcQ/NlXTctlzevTcf
+# Q3jmeLXNKAQgo6rxS8SIKZEOgNER/N1cdm5PXg5FRkFuDbDqOJqxOtoJcRD8HHm0
+# gHusafT9nLYMFivxf1sJPZtb4hbKE4FtAC44DagpjyzhsvRaqQGvFZwsL0kb2yK7
+# w/54lFHDhrGCiF3wPbRRoXkzKy57udwgCRNx62oZW8/opTBXLIlJP7nPf8m/PiJo
+# Y1OavWl0rMUdPH+S4MO8HNgEdTCCBTAwggQYoAMCAQICEAQJGBtf1btmdVNDtW+V
+# UAgwDQYJKoZIhvcNAQELBQAwZTELMAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lD
+# ZXJ0IEluYzEZMBcGA1UECxMQd3d3LmRpZ2ljZXJ0LmNvbTEkMCIGA1UEAxMbRGln
+# aUNlcnQgQXNzdXJlZCBJRCBSb290IENBMB4XDTEzMTAyMjEyMDAwMFoXDTI4MTAy
+# MjEyMDAwMFowcjELMAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZ
+# MBcGA1UECxMQd3d3LmRpZ2ljZXJ0LmNvbTExMC8GA1UEAxMoRGlnaUNlcnQgU0hB
+# MiBBc3N1cmVkIElEIENvZGUgU2lnbmluZyBDQTCCASIwDQYJKoZIhvcNAQEBBQAD
+# ggEPADCCAQoCggEBAPjTsxx/DhGvZ3cH0wsxSRnP0PtFmbE620T1f+Wondsy13Hq
+# dp0FLreP+pJDwKX5idQ3Gde2qvCchqXYJawOeSg6funRZ9PG+yknx9N7I5TkkSOW
+# kHeC+aGEI2YSVDNQdLEoJrskacLCUvIUZ4qJRdQtoaPpiCwgla4cSocI3wz14k1g
+# GL6qxLKucDFmM3E+rHCiq85/6XzLkqHlOzEcz+ryCuRXu0q16XTmK/5sy350OTYN
+# kO/ktU6kqepqCquE86xnTrXE94zRICUj6whkPlKWwfIPEvTFjg/BougsUfdzvL2F
+# sWKDc0GCB+Q4i2pzINAPZHM8np+mM6n9Gd8lk9ECAwEAAaOCAc0wggHJMBIGA1Ud
+# EwEB/wQIMAYBAf8CAQAwDgYDVR0PAQH/BAQDAgGGMBMGA1UdJQQMMAoGCCsGAQUF
+# BwMDMHkGCCsGAQUFBwEBBG0wazAkBggrBgEFBQcwAYYYaHR0cDovL29jc3AuZGln
+# aWNlcnQuY29tMEMGCCsGAQUFBzAChjdodHRwOi8vY2FjZXJ0cy5kaWdpY2VydC5j
+# b20vRGlnaUNlcnRBc3N1cmVkSURSb290Q0EuY3J0MIGBBgNVHR8EejB4MDqgOKA2
+# hjRodHRwOi8vY3JsNC5kaWdpY2VydC5jb20vRGlnaUNlcnRBc3N1cmVkSURSb290
+# Q0EuY3JsMDqgOKA2hjRodHRwOi8vY3JsMy5kaWdpY2VydC5jb20vRGlnaUNlcnRB
+# c3N1cmVkSURSb290Q0EuY3JsME8GA1UdIARIMEYwOAYKYIZIAYb9bAACBDAqMCgG
+# CCsGAQUFBwIBFhxodHRwczovL3d3dy5kaWdpY2VydC5jb20vQ1BTMAoGCGCGSAGG
+# /WwDMB0GA1UdDgQWBBRaxLl7KgqjpepxA8Bg+S32ZXUOWDAfBgNVHSMEGDAWgBRF
+# 66Kv9JLLgjEtUYunpyGd823IDzANBgkqhkiG9w0BAQsFAAOCAQEAPuwNWiSz8yLR
+# FcgsfCUpdqgdXRwtOhrE7zBh134LYP3DPQ/Er4v97yrfIFU3sOH20ZJ1D1G0bqWO
+# WuJeJIFOEKTuP3GOYw4TS63XX0R58zYUBor3nEZOXP+QsRsHDpEV+7qvtVHCjSSu
+# JMbHJyqhKSgaOnEoAjwukaPAJRHinBRHoXpoaK+bp1wgXNlxsQyPu6j4xRJon89A
+# y0BEpRPw5mQMJQhCMrI2iiQC/i9yfhzXSUWW6Fkd6fp0ZGuy62ZD2rOwjNXpDd32
+# ASDOmTFjPQgaGLOBm0/GkxAG/AeB+ova+YJJ92JuoVP6EpQYhS6SkepobEQysmah
+# 5xikmmRR7zCCBkcwggUvoAMCAQICEAM+1e2gZdG4yR38+Spsm9gwDQYJKoZIhvcN
+# AQELBQAwcjELMAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcG
+# A1UECxMQd3d3LmRpZ2ljZXJ0LmNvbTExMC8GA1UEAxMoRGlnaUNlcnQgU0hBMiBB
+# c3N1cmVkIElEIENvZGUgU2lnbmluZyBDQTAeFw0xODEyMTgwMDAwMDBaFw0yMTEy
+# MjIxMjAwMDBaMIGDMQswCQYDVQQGEwJVUzEWMBQGA1UECBMNTmV3IEhhbXBzaGly
+# ZTESMBAGA1UEBxMJV29sZmVib3JvMSMwIQYDVQQKExpQeXRob24gU29mdHdhcmUg
+# Rm91bmRhdGlvbjEjMCEGA1UEAxMaUHl0aG9uIFNvZnR3YXJlIEZvdW5kYXRpb24w
+# ggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCqvaRLsnW5buglHGWx2sRM
+# CMpqt+gflMjw9ZJPphvbE+ig/u8dPiJpVfIvkvN7V/ncnDrtKn67nbh8ld/fSodW
+# IRbG6bLZFYbSdyJTZ36YyrOOVoBZJk0XS7hFy/IMmiQRXRFQ6ojkIbnM8jdb25Do
+# uJSTccJhbqSkfXvsDlPenD8+jw7woSskafVqdqq0ggKr33JLGsxp3/aE8wFF/o11
+# qHt/sc+fWCRJJMCh6PK6oXmH4HSojj4krn5Uu/Prn1VNsBYmxhqSTFnFVZikW/gp
+# 5BJLCijQPMy+YRGxPM29UExaG706uIk2D5B8WZ/3rNVO73dxn6vvEyltfJ8g4YqE
+# cxpG5nyKG5YjHeAj1YcMVfp8EpHz4eWF2RqIERYixdGjL4RBTIrvNSz4Wo6jaxFi
+# 21uzwxMX1gMoVnDI+Of1af6AsZ3k1QRXI28P1BUYES03u/Hztt24lQHwXgPKUSwy
+# 1lN+PD9q7oCY6ead4rlRypIm7BHJloY2TvLeqPTq63H4dNOoeCL3vlSnF/KvACqS
+# i+hkRYFVKm+S7w9WGQFdwuY17owQeUWJoyiIAMB4qZflEVGQ35WuZgZODjNqPF90
+# d4hjxO8t/jy1N+adAl33yB4lC//TU1TL8XG7CoC5ORp7Pk2XUvE/QKlMeGCHM7gV
+# EPiK1PbCpOHiOmiPD1BmewIDAQABo4IBxTCCAcEwHwYDVR0jBBgwFoAUWsS5eyoK
+# o6XqcQPAYPkt9mV1DlgwHQYDVR0OBBYEFPwqv37Uvqzzgpykz3siATu4jwfyMA4G
+# A1UdDwEB/wQEAwIHgDATBgNVHSUEDDAKBggrBgEFBQcDAzB3BgNVHR8EcDBuMDWg
+# M6Axhi9odHRwOi8vY3JsMy5kaWdpY2VydC5jb20vc2hhMi1hc3N1cmVkLWNzLWcx
+# LmNybDA1oDOgMYYvaHR0cDovL2NybDQuZGlnaWNlcnQuY29tL3NoYTItYXNzdXJl
+# ZC1jcy1nMS5jcmwwTAYDVR0gBEUwQzA3BglghkgBhv1sAwEwKjAoBggrBgEFBQcC
+# ARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzAIBgZngQwBBAEwgYQGCCsG
+# AQUFBwEBBHgwdjAkBggrBgEFBQcwAYYYaHR0cDovL29jc3AuZGlnaWNlcnQuY29t
+# ME4GCCsGAQUFBzAChkJodHRwOi8vY2FjZXJ0cy5kaWdpY2VydC5jb20vRGlnaUNl
+# cnRTSEEyQXNzdXJlZElEQ29kZVNpZ25pbmdDQS5jcnQwDAYDVR0TAQH/BAIwADAN
+# BgkqhkiG9w0BAQsFAAOCAQEAS3WhLbVfRrGJp8+PJj6+ViqNYq5S79gW5hYgSrqJ
+# FFoVps0OGP1EEVAX9omITmaytAQ58APr/qBVIf3WVlYGqDo0R4b1P1JduIA+8n0I
+# RYWx2RdSuNtaG8Ke5nuSpS5TkEC6YjVBFuliBkvdQD6JleSaNsaHWWfytSFYjFsF
+# gvhKDaeqkHjinsJQViQ+P8xvBTaC8FXaleOPlZqyShm2wAIy/mDjYE2hUuhECL56
+# /qzTs8634m0dEibzuVPK5zzCHSzBM9TCSwpstTVl2P0Kmq3Nee5UTTDnR7Em9FIr
+# dW3iD7S+KCkjeo+YN2mR/37gy/LRcw1yqu2HDbRH4+QiUzGCBVwwggVYAgEBMIGG
+# MHIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsT
+# EHd3dy5kaWdpY2VydC5jb20xMTAvBgNVBAMTKERpZ2lDZXJ0IFNIQTIgQXNzdXJl
+# ZCBJRCBDb2RlIFNpZ25pbmcgQ0ECEAM+1e2gZdG4yR38+Spsm9gwDQYJYIZIAWUD
+# BAIBBQCggZgwGQYJKoZIhvcNAQkDMQwGCisGAQQBgjcCAQQwHAYKKwYBBAGCNwIB
+# CzEOMAwGCisGAQQBgjcCARUwLAYKKwYBBAGCNwIBDDEeMBygGoAYAFAAeQB0AGgA
+# bwBuACAAMwAuADkALgAwMC8GCSqGSIb3DQEJBDEiBCAGueLiZxG/uwwkezGlE6NG
+# ik7PbC5BWsmef6UPtfvL6DANBgkqhkiG9w0BAQEFAASCAgCmlnDsuHhfTf6Nrazl
+# nJs0izDY16fS2h6UJ0ihdy48JIUQAWSVIcvnYtkZ42IYgT3JIHalcv6qPQIElpaL
+# CCeR1HWT2qQLLJbQxQv3J0gzffrJkn+1u5FB3y9WCpQLS7PhfItXlZhWMjpbLNIU
+# miJ0xstY/jyzY1Kt9HyF6ZXqo3BMSCV6mbZLXxlanNAuptxbJEzqOenNL0IQ2Vx8
+# 3UlBnqGnRfkyB9TjF73SHCiF44V3PDOo/HIxzM43v6H3Qznn5pdVYUf8w02k+jFS
+# jXRflnKZDd95PVNTGXUGpr2fE1rQcK+a09NkyXtKQQizKPauZ1oHjksV0GvN4h5z
+# Vg0wYJN+akYzCPY7q+tL4hDmPxXgmZgBifqyDT/5g6FamNsjmAvhCAeqkWNhq/qb
+# ecRPBDI6p3N1cFAEQmMsswN4cpK7tmG4mOKjJozc+yn2K7e67amJc6rI1FFJ4Z6Q
+# bbMK6wDWw4hr0FZu/UuTr151m3gFXuRWQmE2z8seKT/CS/Qu+FPwPdB0Y4KJrdzu
+# i5xWtlAfO53Bbvj0zI+f+MU5MBSw/uz/N/UltMDRGEz1NxiXDyxI9dzZwLItm7LC
+# f6fAlTN2I8c/FJ0mVRysli1clwuggdqOMTsjyBxTANXaxMg3O7BkbZVt2MFASnuF
+# TjoSqcY1rryaCs3Tr5dXnIIDaKGCAgswggIHBgkqhkiG9w0BCQYxggH4MIIB9AIB
+# ATByMF4xCzAJBgNVBAYTAlVTMR0wGwYDVQQKExRTeW1hbnRlYyBDb3Jwb3JhdGlv
+# bjEwMC4GA1UEAxMnU3ltYW50ZWMgVGltZSBTdGFtcGluZyBTZXJ2aWNlcyBDQSAt
+# IEcyAhAOz/Q4yP6/NW4E2GqYGxpQMAkGBSsOAwIaBQCgXTAYBgkqhkiG9w0BCQMx
+# CwYJKoZIhvcNAQcBMBwGCSqGSIb3DQEJBTEPFw0yMDEwMDUxNTQ1MjlaMCMGCSqG
+# SIb3DQEJBDEWBBRra0P9KGMrllTs7BUKY5/9M2+k5DANBgkqhkiG9w0BAQEFAASC
+# AQBjfGRZMDtH8pawNQ1Go21uB4YZ34oTDuo0/aYGPVBORJhMtFseh+oMPSbw1PZq
+# pzA0ZmKU2GXLyC2pRRiScVG3bV7Maeq8jZq95dZpzGG4vlfhAfb1u/d6NTTq4+53
+# 5zVqwmsCJeSvOymE18MiM+eC9JVYK6OR8km2d0/lqi+q+/4L/4XkpxS7z+2FwpnS
+# 1/HgIbgsvojt8viDjpfc0vkiWS8bymyTokFwhES4v2YGI+FqXbWdAeQR+rAlKVtd
+# /slNskA83aeom7iz6jc3sQs2frWt3Rrxux2YSREFEY0508ZzlI0iTLLpflVaewxg
+# VbwCut7qb3zyI8S5Sl4milVC
+# SIG # End signature block
diff --git a/venv1/Scripts/activate b/venv1/Scripts/activate
new file mode 100644
index 0000000..ab38ddb
--- /dev/null
+++ b/venv1/Scripts/activate
@@ -0,0 +1,66 @@
+# This file must be used with "source bin/activate" *from bash*
+# you cannot run it directly
+
+deactivate () {
+ # reset old environment variables
+ if [ -n "${_OLD_VIRTUAL_PATH:-}" ] ; then
+ PATH="${_OLD_VIRTUAL_PATH:-}"
+ export PATH
+ unset _OLD_VIRTUAL_PATH
+ fi
+ if [ -n "${_OLD_VIRTUAL_PYTHONHOME:-}" ] ; then
+ PYTHONHOME="${_OLD_VIRTUAL_PYTHONHOME:-}"
+ export PYTHONHOME
+ unset _OLD_VIRTUAL_PYTHONHOME
+ fi
+
+ # This should detect bash and zsh, which have a hash command that must
+ # be called to get it to forget past commands. Without forgetting
+ # past commands the $PATH changes we made may not be respected
+ if [ -n "${BASH:-}" -o -n "${ZSH_VERSION:-}" ] ; then
+ hash -r 2> /dev/null
+ fi
+
+ if [ -n "${_OLD_VIRTUAL_PS1:-}" ] ; then
+ PS1="${_OLD_VIRTUAL_PS1:-}"
+ export PS1
+ unset _OLD_VIRTUAL_PS1
+ fi
+
+ unset VIRTUAL_ENV
+ if [ ! "${1:-}" = "nondestructive" ] ; then
+ # Self destruct!
+ unset -f deactivate
+ fi
+}
+
+# unset irrelevant variables
+deactivate nondestructive
+
+VIRTUAL_ENV="C:\Users\Admin\Documents\IMT Atlantique\UE -Conteneurisation-\Séance 1\UE-AD-A1-REST\venv1"
+export VIRTUAL_ENV
+
+_OLD_VIRTUAL_PATH="$PATH"
+PATH="$VIRTUAL_ENV/Scripts:$PATH"
+export PATH
+
+# unset PYTHONHOME if set
+# this will fail if PYTHONHOME is set to the empty string (which is bad anyway)
+# could use `if (set -u; : $PYTHONHOME) ;` in bash
+if [ -n "${PYTHONHOME:-}" ] ; then
+ _OLD_VIRTUAL_PYTHONHOME="${PYTHONHOME:-}"
+ unset PYTHONHOME
+fi
+
+if [ -z "${VIRTUAL_ENV_DISABLE_PROMPT:-}" ] ; then
+ _OLD_VIRTUAL_PS1="${PS1:-}"
+ PS1="(venv1) ${PS1:-}"
+ export PS1
+fi
+
+# This should detect bash and zsh, which have a hash command that must
+# be called to get it to forget past commands. Without forgetting
+# past commands the $PATH changes we made may not be respected
+if [ -n "${BASH:-}" -o -n "${ZSH_VERSION:-}" ] ; then
+ hash -r 2> /dev/null
+fi
diff --git a/venv1/Scripts/activate.bat b/venv1/Scripts/activate.bat
new file mode 100644
index 0000000..9a459d3
--- /dev/null
+++ b/venv1/Scripts/activate.bat
@@ -0,0 +1,33 @@
+@echo off
+
+rem This file is UTF-8 encoded, so we need to update the current code page while executing it
+for /f "tokens=2 delims=:." %%a in ('"%SystemRoot%\System32\chcp.com"') do (
+ set _OLD_CODEPAGE=%%a
+)
+if defined _OLD_CODEPAGE (
+ "%SystemRoot%\System32\chcp.com" 65001 > nul
+)
+
+set VIRTUAL_ENV=C:\Users\Admin\Documents\IMT Atlantique\UE -Conteneurisation-\Séance 1\UE-AD-A1-REST\venv1
+
+if not defined PROMPT set PROMPT=$P$G
+
+if defined _OLD_VIRTUAL_PROMPT set PROMPT=%_OLD_VIRTUAL_PROMPT%
+if defined _OLD_VIRTUAL_PYTHONHOME set PYTHONHOME=%_OLD_VIRTUAL_PYTHONHOME%
+
+set _OLD_VIRTUAL_PROMPT=%PROMPT%
+set PROMPT=(venv1) %PROMPT%
+
+if defined PYTHONHOME set _OLD_VIRTUAL_PYTHONHOME=%PYTHONHOME%
+set PYTHONHOME=
+
+if defined _OLD_VIRTUAL_PATH set PATH=%_OLD_VIRTUAL_PATH%
+if not defined _OLD_VIRTUAL_PATH set _OLD_VIRTUAL_PATH=%PATH%
+
+set PATH=%VIRTUAL_ENV%\Scripts;%PATH%
+
+:END
+if defined _OLD_CODEPAGE (
+ "%SystemRoot%\System32\chcp.com" %_OLD_CODEPAGE% > nul
+ set _OLD_CODEPAGE=
+)
diff --git a/venv1/Scripts/deactivate.bat b/venv1/Scripts/deactivate.bat
new file mode 100644
index 0000000..1205c61
--- /dev/null
+++ b/venv1/Scripts/deactivate.bat
@@ -0,0 +1,21 @@
+@echo off
+
+if defined _OLD_VIRTUAL_PROMPT (
+ set "PROMPT=%_OLD_VIRTUAL_PROMPT%"
+)
+set _OLD_VIRTUAL_PROMPT=
+
+if defined _OLD_VIRTUAL_PYTHONHOME (
+ set "PYTHONHOME=%_OLD_VIRTUAL_PYTHONHOME%"
+ set _OLD_VIRTUAL_PYTHONHOME=
+)
+
+if defined _OLD_VIRTUAL_PATH (
+ set "PATH=%_OLD_VIRTUAL_PATH%"
+)
+
+set _OLD_VIRTUAL_PATH=
+
+set VIRTUAL_ENV=
+
+:END
diff --git a/venv1/Scripts/easy_install-3.9.exe b/venv1/Scripts/easy_install-3.9.exe
new file mode 100644
index 0000000000000000000000000000000000000000..ad5ba1d09700c56944cb01838574cb2dcbed7171
GIT binary patch
literal 106432
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