From fdec3b37dc77bb9f73b7d890dd7fc7409e62f2f8 Mon Sep 17 00:00:00 2001
From: "cc02503@surrey.ac.uk" <cc02503@surrey.ac.uk>
Date: Fri, 29 Mar 2024 21:40:32 +0000
Subject: [PATCH] Update - implemented the event driven architecture with kafka
 event store and streaming service for asynchronous communication between the
 product and user microservice

---
 .../app/__pycache__/config.cpython-311.pyc    | Bin 351 -> 390 bytes
 Product_MicroService_Group3/app/config.py     |   4 +-
 .../__pycache__/getReviews.cpython-311.pyc    | Bin 0 -> 2389 bytes
 .../app/controllers/getReviews.py             |  44 ++++++++++++++
 .../app/events/__init__.py                    |   0
 Product_MicroService_Group3/app/index.py      |  11 ++++
 .../__pycache__/getReviews.cpython-311.pyc    | Bin 0 -> 2521 bytes
 .../updateUsername.cpython-311.pyc            | Bin 0 -> 2407 bytes
 .../app/models/getReviews.py                  |  42 ++++++++++++++
 .../app/models/updateUsername.py              |  48 ++++++++++++++++
 .../app/subscribers/__init__.py               |   5 ++
 .../__pycache__/__init__.cpython-311.pyc      | Bin 0 -> 523 bytes
 .../updateUsernameSubscriber.cpython-311.pyc  | Bin 0 -> 2125 bytes
 .../subscribers/updateUsernameSubscriber.py   |  34 +++++++++++
 .../app/__pycache__/config.cpython-311.pyc    | Bin 0 -> 348 bytes
 User_MicroService_Group3/app/config.py        |   7 +++
 .../changePasswordController.cpython-311.pyc  | Bin 3885 -> 3887 bytes
 .../deleteProfileController.cpython-311.pyc   | Bin 1360 -> 1362 bytes
 .../fetchUsernameController.cpython-311.pyc   | Bin 0 -> 1293 bytes
 .../loginController.cpython-311.pyc           | Bin 3422 -> 3424 bytes
 .../logoutController.cpython-311.pyc          | Bin 1096 -> 1099 bytes
 .../showReviewsController.cpython-311.pyc     | Bin 0 -> 2018 bytes
 .../signupController.cpython-311.pyc          | Bin 2617 -> 2594 bytes
 .../updateProfileController.cpython-311.pyc   | Bin 1994 -> 2445 bytes
 .../controllers/changePasswordController.py   |  23 +++++---
 .../controllers/deleteProfileController.py    |   8 ++-
 .../controllers/fetchUsernameController.py    |  28 +++++++++
 .../app/controllers/getUsersController.py     |  18 ++++++
 .../app/controllers/loginController.py        |   8 ++-
 .../app/controllers/logoutController.py       |   8 ++-
 .../app/controllers/showReviewsController.py  |  54 ++++++++++++++++++
 .../app/controllers/signupController.py       |   9 +--
 .../controllers/updateProfileController.py    |  21 ++++---
 .../app/events/__init__.py                    |   0
 .../__pycache__/__init__.cpython-311.pyc      | Bin 0 -> 272 bytes
 .../eventDefinitions.cpython-311.pyc          | Bin 0 -> 492 bytes
 .../app/events/eventDefinitions.py            |   5 ++
 User_MicroService_Group3/app/index.py         |  28 ++++++++-
 .../changePassword.cpython-311.pyc            | Bin 5555 -> 5555 bytes
 .../__pycache__/fetchUsername.cpython-311.pyc | Bin 0 -> 2209 bytes
 .../__pycache__/getUsers.cpython-311.pyc      | Bin 0 -> 272 bytes
 .../__pycache__/updateProfile.cpython-311.pyc | Bin 4493 -> 4493 bytes
 .../app/models/changePassword.py              |  10 ++--
 .../app/models/fetchUsername.py               |  39 +++++++++++++
 .../app/models/getUsers.py                    |  38 ++++++++++++
 .../app/publishers/__init__.py                |   1 +
 .../__pycache__/__init__.cpython-311.pyc      | Bin 0 -> 369 bytes
 .../kafkaPublishers.cpython-311.pyc           | Bin 0 -> 2334 bytes
 .../app/publishers/kafkaPublishers.py         |  44 ++++++++++++++
 49 files changed, 500 insertions(+), 37 deletions(-)
 create mode 100644 Product_MicroService_Group3/app/controllers/__pycache__/getReviews.cpython-311.pyc
 create mode 100644 Product_MicroService_Group3/app/controllers/getReviews.py
 create mode 100644 Product_MicroService_Group3/app/events/__init__.py
 create mode 100644 Product_MicroService_Group3/app/models/__pycache__/getReviews.cpython-311.pyc
 create mode 100644 Product_MicroService_Group3/app/models/__pycache__/updateUsername.cpython-311.pyc
 create mode 100644 Product_MicroService_Group3/app/models/getReviews.py
 create mode 100644 Product_MicroService_Group3/app/models/updateUsername.py
 create mode 100644 Product_MicroService_Group3/app/subscribers/__init__.py
 create mode 100644 Product_MicroService_Group3/app/subscribers/__pycache__/__init__.cpython-311.pyc
 create mode 100644 Product_MicroService_Group3/app/subscribers/__pycache__/updateUsernameSubscriber.cpython-311.pyc
 create mode 100644 Product_MicroService_Group3/app/subscribers/updateUsernameSubscriber.py
 create mode 100644 User_MicroService_Group3/app/__pycache__/config.cpython-311.pyc
 create mode 100644 User_MicroService_Group3/app/controllers/__pycache__/fetchUsernameController.cpython-311.pyc
 create mode 100644 User_MicroService_Group3/app/controllers/__pycache__/showReviewsController.cpython-311.pyc
 create mode 100644 User_MicroService_Group3/app/controllers/fetchUsernameController.py
 create mode 100644 User_MicroService_Group3/app/controllers/getUsersController.py
 create mode 100644 User_MicroService_Group3/app/controllers/showReviewsController.py
 create mode 100644 User_MicroService_Group3/app/events/__init__.py
 create mode 100644 User_MicroService_Group3/app/events/__pycache__/__init__.cpython-311.pyc
 create mode 100644 User_MicroService_Group3/app/events/__pycache__/eventDefinitions.cpython-311.pyc
 create mode 100644 User_MicroService_Group3/app/events/eventDefinitions.py
 create mode 100644 User_MicroService_Group3/app/models/__pycache__/fetchUsername.cpython-311.pyc
 create mode 100644 User_MicroService_Group3/app/models/__pycache__/getUsers.cpython-311.pyc
 create mode 100644 User_MicroService_Group3/app/models/fetchUsername.py
 create mode 100644 User_MicroService_Group3/app/models/getUsers.py
 create mode 100644 User_MicroService_Group3/app/publishers/__init__.py
 create mode 100644 User_MicroService_Group3/app/publishers/__pycache__/__init__.cpython-311.pyc
 create mode 100644 User_MicroService_Group3/app/publishers/__pycache__/kafkaPublishers.cpython-311.pyc
 create mode 100644 User_MicroService_Group3/app/publishers/kafkaPublishers.py

diff --git a/Product_MicroService_Group3/app/__pycache__/config.cpython-311.pyc b/Product_MicroService_Group3/app/__pycache__/config.cpython-311.pyc
index f5dbbfc7766e0722ceb9c91c99c512ea13f2f156..24ec9fb0533112f07ac3fe8e36eedc6a3f03e748 100644
GIT binary patch
delta 147
zcmcc5)W*!aoR^o20SIDE8Pbv`@=AKi0XfqdQW#Pga~Pr+QkbF`Q<$TeQdpvxQ&^)|
zQW%37G}&H)bohnbVskIbFD)?6>=b5TsN&1XPfpCq$S*FjvNW(X(qx?&Bg=P-$J^1(
o+c7@aH7LwAXkz6?E*_v(Mj$TMm~6tR#P@(tu7L*xi$Kl*0GsF{IsgCw

delta 107
zcmZo;zR$$FoR^o20SF8%f2BH3<drm&0&=D^q%fo~<}gGtq%cJ>rZ7h_rLaUXr!WRH
zXtKTpsrC!G#pYg=Us_<C*(uDxpvf|^Kz8Enja=M7IYuBZR-PQjsKnX8(!f&03FHF+
D>K+!v

diff --git a/Product_MicroService_Group3/app/config.py b/Product_MicroService_Group3/app/config.py
index c00614d7..5ddee913 100644
--- a/Product_MicroService_Group3/app/config.py
+++ b/Product_MicroService_Group3/app/config.py
@@ -4,4 +4,6 @@ import os
 DEBUG = True
 SECRET_KEY = "Group3"
 
-PORT = 5001
\ No newline at end of file
+PORT = 5001
+
+KAFKA_SERVER= "localhost:9092"
\ No newline at end of file
diff --git a/Product_MicroService_Group3/app/controllers/__pycache__/getReviews.cpython-311.pyc b/Product_MicroService_Group3/app/controllers/__pycache__/getReviews.cpython-311.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..5ccdb50ab470f1f972531278c526c941297e5bd9
GIT binary patch
literal 2389
zcma(SOK2NMbVkxjtFP_E`MD|H+769sM;1=vCdM(OPMngG*i=qKgg~r!NA}wLQD;|n
zEbQV#3ZVqrTSPB4J)|i~A(R$+ZF*>rtFSa-!C)vo<fak=A*a4seQY_0_Axv2KJ(tp
zyx)Eok4F%|=Y6Qq&mr^|BbpFsATNFd<Svqtj8&xJEY^HkpXSf{wLmtYaaj&CnNJOB
zp=`**{VK18vtf*Uh+sKDBKLd<J%Fzc*(ix_#+uabRp#X2JboBz-!JpG&^_4pptUs{
z2g_kO{4jD410TLRWD|1q7Rq+Wu?$MapEG8XbHg8~B~qk{Zn>dF)6kW|svDx@(-JW)
zH^4Y<$Rwtz7<v-B(RpI!DOpy?iV0-=BeAd~&QL=xNrbv#kbdk5%ln3l9@iRf@!Y`7
zbY>Q`LK?9a4B3<#7xNZB%<OydElhWj)w(u9i!EHn?N3@qYlx0o&0v7$BD3Lv>|64j
zO8cyElZRmc9t+rt?vn1Y4*~P9VFhQ99FV!j8f0rSbkz-&OhWUDOqm7dG|w$AM<_L@
z8_-LtT0VZmC<!_tvS1m)91&DwejW%#XS68Gf+*DWl0h0`X8hnU3fYF-VBJlWXT*M!
z=yJpJc@5$r&Xc5%COp}$pycOP^XytCd%GaK{$X+~ca70GQCpQ3a??7wK$T^ZyI@Eq
zjp&w{n*phzi)!wg4gzW_)~a9>giMK2vYMMTO4KC6b%QSD&dbZ9F2VID7erMh`aCh&
zORkeSVU|b>x&g0K2w1F#K7U1#sF5LbS&>No5;aQ2lR2?i%t?lBQ3EW%wOZ+6ri!a>
zWalaL5WIjz&NN`!Kre%+<KUg8O0t?5a1sL>m$pNR8tUYx@K$u+or%gPPon*HwEtxU
z^{4L7SNletzEL~Y`**C@7EV@Ur<~X+J9cWj`)wfY{eYjY1<`?{m4dzhm>oL?MAu=v
z=YrjF(dI9{fFn^kp&F8?E*PdYb~b%>1X8za&M+*~qGB-*PG#PbTFD6-LHN8R-UKcr
zF|*PD#(5KDY_V83U?+L^rs?Lc6mRZE&{x`%xxF*2<1kvoo4f4q()2$JwCk?>toSZD
z*Dl4VO&VPDEwXI&p#9W6J43LOCGdam<Y8y4Q1{xDQ3mxRtGj6lp#enSTKBizD!k_3
zt9Jvs@4EjpKhv*cD|iLn^xr@$I2pO>c1k7FGBhaTR`r&wLjKHi*7;ehvJ{ONC9B+X
zrCxIa)S)GqB}oFh02RLaPB}Ph6cuT#9GMZRrC87@$I7AULct`~SozSDsHpYwXC*8&
zYIiIdb@_UWgvJ?QBFeJI<>Zo9G~FQ4B||23pU12BXU<~hxZz^+7&mBmr?}yZHziVJ
zCnp26gQ@V)JVaTvM7M(y$)GYcjRpe~lVy_tKo0^!nOD839}x3Tm^RQ>;^3Fs7n*%E
z^>g5-$S?0#)00km@@e|=ll0|3fXX=OOf@m<BxW~0tocIR(6gStZ-%}ex=$-Z)t(Wj
zXXJLr79Y10?^XFhhaa^0K_G80R63l)C#rnP;ZruBVl1^X?HoN_<wqTU)aFMSOR4la
zM~16>+Tqi7bG+J$cGnQ*hIS_JfOqeAwT^&O_Ka5mH9u&<Y94{7{pveE@WFBP_;_S8
z?teVeIm!Ef<2k^uCOciOpo-=aWhG3RkGw|g#iibyyEKT2YNmFYR=qoOOYA>LS^Bzs
zKCg=!$>-hpPBY8T6<rP*phdj4MthlY=J)RrJ<M<xh}Zl$*e|JMf{p;m8ix5hOmKgU
zpP_O4|BYuTX}6DU)N8j7*6n(}3Rea<7pk4ZPUrAOd>bd8;_fH7+dhzdH1+6=jk~LO
y+`;2DUpJn@HN@tB{K$81hnGUJBe&1lC(hZ?iE4DhiB4?rwLlm{jNY8QhyDvb{#*h8

literal 0
HcmV?d00001

diff --git a/Product_MicroService_Group3/app/controllers/getReviews.py b/Product_MicroService_Group3/app/controllers/getReviews.py
new file mode 100644
index 00000000..87f4f38a
--- /dev/null
+++ b/Product_MicroService_Group3/app/controllers/getReviews.py
@@ -0,0 +1,44 @@
+from flask import Blueprint, jsonify, request, json, session
+from models.getReviews import get_reviews
+
+from kafka import KafkaProducer
+
+
+get_review_bp = Blueprint("getReview",__name__)
+
+@get_review_bp.route("/product/getReview", methods=["POST"])
+def get_review():
+
+    user_id = session.get("user_id")
+
+    if user_id:
+        if request.method == 'POST':    
+
+            #data = request.get_json()
+            #review = data.get("review")
+
+            get_reviews_by_user = get_reviews(user_id)
+
+            send_review_message(get_reviews_by_user)
+
+            return({"reviews" : get_reviews_by_user})
+        
+        else:
+            return {"error" : "null"}
+        
+    else:
+        return {"error" : "You need to be logged in to add a review"}
+    
+
+producer = KafkaProducer(bootstrap_servers = "localhost:9092")
+
+def send_review_message(reviews):
+    metadata =producer.send("customer_reviews", json.dumps(reviews).encode("utf_8"))
+    try:
+        record_metadata = metadata.get(timeout=10)
+        print("Message sent successfully!")
+        print("Topic:", record_metadata.topic)
+        print("Partition:", record_metadata.partition)
+        print("Offset:", record_metadata.offset)
+    except Exception as e:
+        print("Failed to send message:", e)
\ No newline at end of file
diff --git a/Product_MicroService_Group3/app/events/__init__.py b/Product_MicroService_Group3/app/events/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/Product_MicroService_Group3/app/index.py b/Product_MicroService_Group3/app/index.py
index 9f0267b5..79afca3d 100644
--- a/Product_MicroService_Group3/app/index.py
+++ b/Product_MicroService_Group3/app/index.py
@@ -6,10 +6,12 @@ from flask import jsonify
 from config import DEBUG, SECRET_KEY, PORT
 import os
 import requests
+import subscribers
 
 from controllers.getProductController import display_product_bp
 from controllers.addReviewController import add_review_bp
 from controllers.productHomeController import product_home_bp
+from controllers.getReviews import get_review_bp
 
 
 
@@ -24,6 +26,9 @@ app.secret_key = SECRET_KEY
 # Read user microservice URL from environment variable
 USER_MICROSERVICE_URL = os.getenv('USER_MICROSERVICE_URL', 'http://127.0.0.1:5000')
 
+
+#subscribers.consume_username_updated_event()
+
 @app.route('/product', methods=['POST'])
 def get_session_id():
     session_id = session.get('user_id')
@@ -43,8 +48,14 @@ def index():
 app.register_blueprint(display_product_bp)
 app.register_blueprint(add_review_bp)
 app.register_blueprint(product_home_bp)
+app.register_blueprint(get_review_bp)
+
+
 
 
 
 if __name__ == '__main__':
+
+    subscribers.start_kafka_consumer()
+
     app.run(debug=DEBUG, port=PORT)
\ No newline at end of file
diff --git a/Product_MicroService_Group3/app/models/__pycache__/getReviews.cpython-311.pyc b/Product_MicroService_Group3/app/models/__pycache__/getReviews.cpython-311.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..4ccf1bdd0dc2a3f16681b83ed686dd3e96875123
GIT binary patch
literal 2521
zcmd58O>YxNbavNkZ-SlFhNOIFl~4&wky9GcL*&p>+q4u25JM@^R>s+#goX94nO!?^
zYFDV`;36bSRVfErDTj(u@dr5c1RQ$kVS_ATt<(ys>LItSQlyAe->mHzCq01FN*&LP
z-`Bj4dGC$=LnzdZV4NOAGhg@+`kf-J!8U=_VE`79f)qwWQ}mnFm>fIBG8E=CF6W!_
z0qnbmrg()(qbR>Zk4{7xCveF$bakc#V7F}OI+m@BGA%Pr)%1&p#lc$r4Gb=#E@ZvH
zy#tJUuo|Pnl$oU$xGg$D8|2tBs&EQZ@s-)7Rv2wzfXcoycLzB4*0~G<S?b58u|YSl
zu-8zTPj0m7FZ;_Z*#=tRA~%mtEntlyeGtt{$)-^n4I#@*RYUV7f6Kx?M2=MgR&NVO
zkdkuXHu{de12=VV{k9l%9@13_d=_{`FZ*BCO9i}aENW$rv0iKY^bcP8{vTe>p?U5+
znq!6_|Nl+)=1|K<l%H6@>D2L5;*6Lmn3j>l<Y;nOJZoa2XLER1oWw;H&kc(tYpMF|
zuy~3XN<p@cCdDI@Cr^mVv=M8Fn1^*`(i1Ypb04H8Q!gkS7vJgVFah$g71rt$Y>Q|X
zmC+~rX)h^g$9jqYV>&Rl1LHa{UmH{SZ~0s7jVQFepU`evp(VHCLA0G#XoW|4r@I}n
zBeVi`{EcWFe<NV0Ydzo}QIvJq*qaVVj5(946UFCu6JruRYf9N%NxmqZ)NzuiMJy!^
zxsb!UWlE=jYv@@`I;#VNn5tD0jTtdrAOx4Bgi#<S7S9>vvUFG}W_1}WV&Y;})382^
zO;Odwb9h=jgXN35p&7F(291pzWKO6uG18b6RT*dACq^MZDrNI|DQ75HGo@K<HB%GI
zm!5aWHPy6aBbPt4FaWF!@iJ@1;+i36HS-VvErC7=&ioj*tH?!Y`y{(zPq0VWCG+lq
z?~C_G?_c@p?Vr>3>B(O{vM<QCf@>FM>|)7Y__S6m+uJKJH=G82tDqY#>`i8^>~t2w
z$AlP!#@cplOkCK1R>$*sc%k7+8WM&q7YJY*B%@t~Ce`r+*EEO|!1GuxSlAI}uqD&W
zba+`aOzimcB?F#&hfh(94xcBgZaH14c^T&|)zG7Y<5R$^^&bbIk$$Q>P=GXNRK*E3
zFD`SXfJw;-G*KtmqI>5VY|<(hn}g7Dceb>{Gszo33BWR4s86_PpU4mV(Km2Q`bMgD
z*TcJ>ga;po2baV9YT<oV|I<i+HQ@Tuj(6E=s4n!}?780aRb^>*S%}qym@UNWk?o5k
zUym$DhH8-^5cPHB?L+o-Gl_qC3H{64t3fx2!h76)6pXlt>DpBfMs6Oze*DXc8xz%u
z`j$RQ9H<BTp9FV54(?tK?yUv)+TL_I;H*7+9ZueeyNKntwYOh|klpjv-7B!cToy)a
z!l*5b)_b>BE&6eLUfmv8^-Ovmt-*NKi-O?aX2bFOVY?>|b6FU#3FEdf-Zt$27Yw_-
zV3T^_cE7r|#<i`jnQ_Sc=ZE*a7eWt0y~#1|!R|<6kb4mGCCAaj!4Oa$jzp3Nxkn78
zJUYk&<<S^N;qj5wFb8kjPFhm@jFvSo6Z)_@I~$E3qXkIYD%1RfLu;7!hgWih{s<D<
z;a*KX7vgZLpy5MgKhWq?X&!?O9A%iND0J2P)X@&RbJo!TyK}n!L1w^3n>Wwc-?ao|
A0RR91

literal 0
HcmV?d00001

diff --git a/Product_MicroService_Group3/app/models/__pycache__/updateUsername.cpython-311.pyc b/Product_MicroService_Group3/app/models/__pycache__/updateUsername.cpython-311.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..d55720a3e7872e81ac56a1facc02ba57c682325d
GIT binary patch
literal 2407
zcmcf@TWH%>^vbgA>%_6+WNqd;50eBkcWJ`dMnl(TIElB8by;Z=vIap=q?=T&EO}Q_
z5(j6Lv5%}2x<R3XG3Zyj(S7uD-%a{Ckb@ycFer?D>`xF1re8bPj-5w47%koL)zNw1
zbIyIp_gh+;5Ww%J(c+FDp+6Z@2j3pCI|#%bq#%XUP?nqHI7a(4-<%KLyvAq!bAFKd
zzd>_?;+sM#;cw=e;@sd>)6mt${3Os#vZ3olw&s-uncEA^UIIKkJiB9n@1PK}4ruRz
z;sHE0Smz4d-2>XX9HAq2z5*m0Z>ZOK;C%;pzrwEz1>fCzi499e6oi7mz%Tmlf%ZYe
zf<rJj%kw!nJU45EBB)%!N8f-MpsCNpQI7&gk3sbRWIKhXP#?0Y%T|kgHBg_SA5m#N
zU`6XZLQ0?z_!0f&y9Zr+(CA#X7QAn@PaVxn2`X6SWZz|2^7X)1f!A48ZH5)jYTM7}
z1r>!}xuT~3yP_4e%3nq+TpxN}{aZoxIa1A&ZqPOfomUk%tdo^_#^_R(tbH+aaUwmP
zNh%A*&?U00k`*(pE0-io)tAhsB*0W=y834H%%0o1<cC$+?D@>4OhY?vo0gF!^pgqD
zyTL3mO=*d&b=AF+c21Ejq9jdQmO;5_Yg&G-Z$h%91<52yLa9NMs=jB}Nb*e56*5e>
z7CCIYc4|f^t2wwpAZX3okY$?!_o66ktw+sMO_UulHvmqiLERu(C9-W15E$94YPo`}
z878o~ya87f4KZUOM^)W&F*P)8L6Wbzq0FjGa+Yf7si5nJ5~aq)1~STyC1vN)#r3wk
zv05vtCC-0o6PkB9Vg|v8wHe^quj6M#);Lp?vU&N6__<CdsJcwV2}8ECM7K=wB4`a=
z(!?1Z6x39$e9~A<PT7=_yf|(^O(Z#M&}(8^S(bDe+A@Ac(lnwk5tDUjmMkQviF`#j
zG-F965Rn>+4cGB!s!WY3LYGyU%zsP`JNK?A<#J-yP>5!VwdCu|I+V-1(F66ceMR4d
zQdl|W3Ain<BhNn|^!#<K=X>$CxY1OOC3a%H+p*qatiKfN-v~TuJN{k%_V7lq+}`m+
zq|`pJfxUpgEAHU97e=Azt;mgt)A82NBM)btljn+fw1h_;JnCT-YTv=}Z5%J+L<uJx
zoOse2cRD|CqG!Es6mIhn7fO`FZMQDmxbW@d&B=|)a`Q1J>?wzj?}R(I!=1%&cPZTM
zRENidrt&lao;S~Wh!+O;(I2?QiJX3z1_YysM@o3a!6Rkdwu2MfI8nr1CEVrUu5xRK
zbK;~EecQo@hS&PC2~{eUr!f?U#Cc(8A5}9-|0X#RNGe^#V<kN1;IV(nXwZqCa`2(y
z1zsT|F9yj#W))bWmuz&UVxEUR@^!jztQ|dSk7fq>N4=@>QGT<T19~&;&kUo@(H5Y$
znp2qpe(OCZ-+G_P9}fsXKOW>6Jv{tTH=hc)!lEXb*C_iY(+D8<L~Y9su~W$|nfbkc
z9PD7SqhH;qzo1<p5$yo<44(xTTO*^i3t0AjG(QCdTZ7}Cpty5*lu^s|>aUF6aSjhJ
Qkm7ng_{(z?(N2i>4^pN<3IG5A

literal 0
HcmV?d00001

diff --git a/Product_MicroService_Group3/app/models/getReviews.py b/Product_MicroService_Group3/app/models/getReviews.py
new file mode 100644
index 00000000..ce8811ec
--- /dev/null
+++ b/Product_MicroService_Group3/app/models/getReviews.py
@@ -0,0 +1,42 @@
+#from app import db
+import pyodbc
+from flask import jsonify
+from models.database_connection import connect_db
+
+#Function to get user info
+def get_reviews(data):
+
+    try: #error handling
+
+        connection = connect_db()
+        cursor = connection.cursor()
+
+        user_id = data
+
+        #Get reviews from database
+        reviews_query = "SELECT CustomerID, Username, Review, rating, ProductID FROM dbo.ReviewsAndRatings WHERE CustomerID= ?"
+        cursor.execute(reviews_query, user_id)
+        reviews = cursor.fetchall()
+
+        reviews_data = [{"CustomerID": row[0], "Username": row[1], "Review": row[2], "rating" : row[3], "ProductID" : row[4]} for row in reviews]
+
+
+
+        #connection.close()
+
+        return (reviews_data)
+    
+    except pyodbc.Error as e: #error handling
+        print(f"Database error in get_review: {e}")
+        return None
+    
+    except Exception as e: #error handling
+        print(f"Unexpected error occured in get_review: {e}")
+        return None
+    
+    finally:
+        if cursor:
+            cursor.close()
+        if connection:
+            connection.close()
+    
\ No newline at end of file
diff --git a/Product_MicroService_Group3/app/models/updateUsername.py b/Product_MicroService_Group3/app/models/updateUsername.py
new file mode 100644
index 00000000..d673f8bc
--- /dev/null
+++ b/Product_MicroService_Group3/app/models/updateUsername.py
@@ -0,0 +1,48 @@
+#from app import db
+from flask import jsonify
+import pyodbc
+from models.database_connection import connect_db
+
+
+def update_username(data):
+
+    try: #error handling
+
+        connection = connect_db()
+        cursor = connection.cursor()
+        
+        user_id = data["user_id"]
+        username = data["new_username"]
+
+        #insert data into user table
+        update_user_query = '''UPDATE dbo.ReviewsAndRatings
+    SET
+        Username= ?
+    WHERE
+        CustomerID= ?'''
+
+        cursor.execute(update_user_query, (username, user_id))
+
+
+        #commit changes to database if no errors
+        connection.commit()
+
+        return {"message" : "Username updated successfully"}
+        
+
+
+    except pyodbc.Error as e: #more error handling
+        print(f"Database error in update_username: {e}")
+        connection.rollback()
+        return {"Error" : "Database error"}
+    
+    except Exception as e: #more error handling
+        print(f"Unexpected error occured in update_username: {e}")
+        connection.rollback()
+        return {"Error" : "Unexpected error"}
+    
+    finally:
+        if cursor:
+            cursor.close()
+        if connection:
+            connection.close()
\ No newline at end of file
diff --git a/Product_MicroService_Group3/app/subscribers/__init__.py b/Product_MicroService_Group3/app/subscribers/__init__.py
new file mode 100644
index 00000000..377b8371
--- /dev/null
+++ b/Product_MicroService_Group3/app/subscribers/__init__.py
@@ -0,0 +1,5 @@
+print("Subscribers package initialized")
+
+from subscribers.updateUsernameSubscriber import consume_username_updated_event
+
+from subscribers.updateUsernameSubscriber import start_kafka_consumer
\ No newline at end of file
diff --git a/Product_MicroService_Group3/app/subscribers/__pycache__/__init__.cpython-311.pyc b/Product_MicroService_Group3/app/subscribers/__pycache__/__init__.cpython-311.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..3983da2bfc76957fedcc9a12c59acbeee1d68af6
GIT binary patch
literal 523
zcmZuuKTAU~5YOvtMHDw@eS=`TxacGzN-IwOfm#X@2x)R{Ltm4}C9hB?zlGmG5x<5X
zpn`*RDmb|b-JDFcQU#C8<rnVmcXzqFm6avp<#c(W{pj!4@c5B<2Bte6+>inRBFSw;
z$b&!M5)m26LK^i8mxV7JdmLZJ9vADRQo35N=PfHxwE%6Bana))NR(Di@l;)bd<#64
zXuKwjws{{|ZUHq9Ad}pIWH12je8j4C93AWNc8{}JG@e$9<5Gr7yYYsdSK9hcZp^sm
zJz$s#i{9LmX(;{iP~D{=&QjhViY`6VP(w8US~J4;qn)Ma-fJ{ZX+wJlTIGg`X(#m@
z5r(vCa<q^%4fg1v9B?f_Ce<!aQ_vl-e%Pc5t>gkkSDVyy6nI87G8c}WD1oL9I8XxE
zF`7Kvraa5&uTdyt;ky{y%7!0{dwrjn!ajzrg)P_vZ{Fi5ie5<Rx-?qYd?Mv%QXY}=
Rgq)53>VzDP{!?7^B%dxfrRo3x

literal 0
HcmV?d00001

diff --git a/Product_MicroService_Group3/app/subscribers/__pycache__/updateUsernameSubscriber.cpython-311.pyc b/Product_MicroService_Group3/app/subscribers/__pycache__/updateUsernameSubscriber.cpython-311.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..ecca0f3a049b16bf2c1abebacb308cdcb80d4cc0
GIT binary patch
literal 2125
zcmc&!&1>976d&!5wAy%`wd=%=y-uno*kljh(7H6C^drGenqb!{{%By?M99+YTDCrx
z8Lh#_1|M=rp~pgdNFgVO;2e7I-%!v7l^DT-p{GI*hTMGWn^|k^tqVPNBt5;EH}gK`
zz4v?B+j|bdc$rhG@5u=L!6(T`9W(Fdf%y?x$dVl7N@Ypne9B3=>2g}|X$QM<Sr$BY
z6gN}O2wry7vI=`;CtJ>1%2QN6XJvr)Sn>iYs(*3=MJeu`F{*3El<%>IODHVlX71dZ
zxuY-Ko&WakJk0Zrx@81JZ!khV!zHk!EUr*uSaasFlj4Vgrr~>6mbk|O&}6K3_#jz=
z|7sE=#P&M13$wk>iqw6c>lMRF?}Dzqjy~9zO=JjJI1o45UU@Bd>)b|LXc|3!ye(}>
zt4ea}MJC}+|1G84&UPy3KasC?Y;L9gu`eB5JlSVux~1UlDe2bPScXo{o|S(8#6moC
zb4SIo>jpCe8<N4a32p4UL)M8SlGC2MgfXKA(pRZi7Q$Gm`qVXo&1>yc+g?peGOD#R
zY-ymy3reL@e6ddbs_j71MeZ#<@awh-neSir{eT73sOwM;>x8mRxe-(+Zf#~CXojn;
z5K4-<IOF)W8kmTCmJMc`V6tl0V*Ft4-oqH%9=O6YN_ok|^19(PNUT`I^eqzORpxu(
zv~O4}mh05^0t(H6ia1uy<0_3a#{tHDiK9@Wh7OL!xzj6*ThL$}{W|q&WeHqn6~o;y
zS1J!ZGEMDuQknKmD10wqm2W`mdxle4@<2eD9c*ZRRa<CKN;WD}euFZiJ@V;V<&L#(
zcqXy5sTIR<h*u*_vpww*S=JVbx#IZ{zD+<Q^{s{(=wI6=^%vm2Y?J6;QNK~2tQhrr
zg*BF$N$q9sR{N&8i#(4D9Z9La5nnkDywii7yoij^QHb(9d~6TM4r<|^2oL>Sd+vmj
zPeQCWu^wR^7!W+24f{W7;+qk^8RDC*{AhUj<KJ>&eyN#Xit<Z4_xA@1he(#k1$ma)
zFI;{8`P;&cH-#I&WSWIrQQ=moUTO^$e%K7Je$*VAjD{wk<yva*v$du=5~(AhI>Kj8
zQ!PYlAyf-3b?B#DQyq)cu~58+J&F2v;4b=i5cvxv{}+gyY1$s{XL|&>ghL1brVEU=
zk)>=Qy#pv)=!JT+`-IyCmS?IxI9NklXXYs1OgXe{jw}QQ4S0_Vbk>r>hu+*AzE2#-
z*Q(TawKb029Vtg<I9DUVVlhj3LC`!WeVlOkqJx}p=o2LaJ!cS?cN^p8;CN0b)B^$U
zjH9eZ3qa!wVu#)qC*II&AR2~`IY9oq?k1YJ6yZ{cOD&uY&y6+lc!bA8Jl+}@{{4e5
z!-3n)f!oo*?VZ{Ekt;j1P{aGU?=2pDg9n@VQiLys$xAPTLBJVVI3&O%R=_PlnKr0g
zbOB2oR_g950VHv@9Uk0n`zkJguJ&#5J`zE_Lc)TG{Yd=`lr<dk1ucS{UkdvU$YENN
zq<!>$*!>=KPeFQsJ`B6x12h_TzlREvayvcz*+=Jh#B-=*C1}GA8C0a<Lv)r1SN{f?
CLIptp

literal 0
HcmV?d00001

diff --git a/Product_MicroService_Group3/app/subscribers/updateUsernameSubscriber.py b/Product_MicroService_Group3/app/subscribers/updateUsernameSubscriber.py
new file mode 100644
index 00000000..4235a17f
--- /dev/null
+++ b/Product_MicroService_Group3/app/subscribers/updateUsernameSubscriber.py
@@ -0,0 +1,34 @@
+from kafka import KafkaConsumer
+
+from config import KAFKA_SERVER
+
+from models.updateUsername import update_username
+
+from threading import Thread
+
+
+import json
+import logging
+
+#This function is called in the "__init__.py" file in the "subscribers" folder
+def consume_username_updated_event():
+    logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
+    logging.info("Consuming username updated event...")
+    consumer = KafkaConsumer("profile_updated_topic", bootstrap_servers=KAFKA_SERVER)
+    for message in consumer:
+        profile_data_str = message.value.decode("utf-8")
+        profile_data = json.loads(profile_data_str)
+        print("I am here")
+        print(profile_data)
+        update_username(profile_data)
+
+def start_kafka_consumer():
+    logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
+    logging.info("Starting Kafka consumer...")
+    print("Hello from kafka consumer")
+    kafka_thread = Thread(target=consume_username_updated_event)
+    kafka_thread.daemon = True  # Daemonize the thread so it will be automatically killed when the main thread exits
+    kafka_thread.start()
+
+# Call the start_kafka_consumer function to start the Kafka consumer thread
+        
\ No newline at end of file
diff --git a/User_MicroService_Group3/app/__pycache__/config.cpython-311.pyc b/User_MicroService_Group3/app/__pycache__/config.cpython-311.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..105819a92eef07108a2fb4558af6e0b1ad972654
GIT binary patch
literal 348
zcmXv|!AiqG5Z$C{wJkY`7f%bGdhy~-M5t+~AllL-6vIM^*=f6&?uOl_kXw%af#45_
ze^hc3Jb5ehRy??=`i7Z#!<%8=n{Bs{MsV{DUEM#c;UDH7*`8?ff+(U!f<i>i(4e)@
zq*hp?hKD-!uWIq$FB^R+vh<uiA0gDSN>iw^-gB>me%bO|XXN^mTlb-~hJ%s+j<(g&
z?$x;<fdZ*Ww8-N*8F1)HwgS=<akc=yRAi`C!J~u(TnkdMWsb!ZdzqAw6GvoH0Uita
zM7nep@fav}=24OWpMk=R<1sv9AL2O|iI_1^`-hV|7E9rQT(KA?zs5<FrX&`8%4TP2
wzB{~J2%05uCEMDnp;MjevZ)z{u|~~eADaeh+C_bB9~Z5UgLYw6A)9*d2j&N7WB>pF

literal 0
HcmV?d00001

diff --git a/User_MicroService_Group3/app/config.py b/User_MicroService_Group3/app/config.py
index e69de29b..358b5ce9 100644
--- a/User_MicroService_Group3/app/config.py
+++ b/User_MicroService_Group3/app/config.py
@@ -0,0 +1,7 @@
+import os
+
+
+DEBUG = True
+SECRET_KEY = "Group3"
+
+PORT = 5000
\ No newline at end of file
diff --git a/User_MicroService_Group3/app/controllers/__pycache__/changePasswordController.cpython-311.pyc b/User_MicroService_Group3/app/controllers/__pycache__/changePasswordController.cpython-311.pyc
index f2bccc2cdba24cef3aa5a38361740cb00752099f..34cc426ee500d1191ecb52b66c1c4517c902dad9 100644
GIT binary patch
delta 170
zcmZ20w_c8KIWI340}yC({YwoJ+{kx@U5N+CExyahz|g?(m5qU4tS5Vh=0!f0D|{*q
z?hn}cJ~FsXX5pB{C^C6I$23Nc$!47Lj3S%EIKMD5#%=cIW@BQ^-yFot#>jULXwC;_
zMn=XD91M)+lMDDnC)e|_0dcyv7bBy=2L=%Nk(q(XmGKIr%LgW~U=kBABijcCIH5FI
HkY5G>xa}(e

delta 190
zcmZ24w^ojCIWI340}!z7_?7yAe<R-&b|p?AxA-n2149GDS2hNIv7YQ1niu(0uJEZe
zxIbX$`^exrnT2B(quAv69Mc%tCYy1}GYV}E<NU(N7`54(n~jMvYjY4U8za{lpgA9y
z85tRGOfKLPpIpbsIk|-|#od#U(cl9Ei2TURz~st!h0)~$6Id{TiI<V>0|T5;;AS-Y
Mz<@~<839cO05bqEp#T5?

diff --git a/User_MicroService_Group3/app/controllers/__pycache__/deleteProfileController.cpython-311.pyc b/User_MicroService_Group3/app/controllers/__pycache__/deleteProfileController.cpython-311.pyc
index 8e06212bf94edd278c153db45bf9c8cb26a0fc10..6ce448acfcb8142341af9ce1dbd5583428925b08 100644
GIT binary patch
delta 106
zcmcb>b%~32IWI340}$AA{7c=pk++MPmlMb<o(Uux7`}3BUcxNR$kzqrePCu}Wc<Lv
uz-T`CB8&9o2P|xp->}%LN;4XKU;q*ynHiWI8Lu!pd|-kJfyIj?fO-L+ZW<8)

delta 102
zcmcb_b%Bd_IWI340}%M`_?7Chk++MPmkr1(o(Uux7{0P?UcxNR$khSlePCu}WV|u?
qB8%+g`z&me-?7-MN--LIU;q*ynHiWI8Lu!pd|-kJfyIj?fcgM%i5c(!

diff --git a/User_MicroService_Group3/app/controllers/__pycache__/fetchUsernameController.cpython-311.pyc b/User_MicroService_Group3/app/controllers/__pycache__/fetchUsernameController.cpython-311.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..993fb4379d90d57d8dccc87743e0bec879754e00
GIT binary patch
literal 1293
zcma)5&1>976ra(z<2dTtj<Y#5mQ!O`XzW9hO9)9?8`2c=0UMLD2!x`U^~%=AW+W|a
za6%3__z+543f`knZi{>Ht^Y!g+OSYFr$A{TIk}iza!KFF-gVcfKBT9a-|x-Ld%rjO
zX>9Bi0{iUlNBT}e=ua`}n{qTb*nq(%B8cDsg}8=8sV0STO%9cs5~?*73r-5OP_OA2
zNr+-1Q)3(U+kyAcY9n-Ht2nEV^uI(Q>I(i<8;&RXOSBCkJN+<J8zn{+RYu+lq@wbX
zFN2IWnIENGUrpl3ueZ6*=#z{lDOUu-^@JvgA4e6;Pp{C_$r8#UH>7+NX3IyDr=<mf
zFZ>7M%7gpWhp<WyY1)WM;tjHZfzU;U_uy}En<&NbIkMHknBZ*~?+oV8P}<iMVpqlb
z!icn1XvDrw)jkINAa+=TXLucN4fZ^aM~KKL&Xdy7V}4ya!OH2_F-w$n**}plQR`9_
z5sm0R2GxywTo)=iK4GGZT=EGw`g*?oT|g>jEM{DZvLLAFOc$68sxna+*AAuRhG>N7
z4l@8|qR@)ML^fO@Zt8MP?0RR3nE)k%w!l98ws_561|qTDu<bSM`w?AYev8^mv6qE3
zN)!75uyN!D_HqOSOZ>EL#dWKiF-F_=Vw|yrT90D3W`99iZsbv7EjHXBpwS9VEI+ay
z(Z|+9>NTP`h*x}?6bCwYeUHUe%38iho!czVnwM?2*|fblN?8ocA*VV`y@p6n+^)p|
zG2d(#WfV>m^<>~)p!XUwr(UgfD%~@)y)&~fZofB>VZMCcnR=~H=lV48pPcKN(_M3>
zXU=RWd!@6R<sZtO+3zp>cws|>=!xl0t2;i|8=u=S{xYXJr?$Sy&&_wug`T;vJCU1L
za^uRrhDznmTyD<f#>@d6jP6xVbG070$r=+Eun@oK4im{8c5E_?2@R6@p^}PTal>&$
zeU8IR1v~hkoX1VBf-)&BD*Xkq^J2d;xDUp4*f0y|4Q9bq+}-3`aQiaGcn@9A|KGER
zF6G0|o5@eVyVD7O{;E59wKsV+N2ND-{104yjm!D@&v#q9jU1P|_+}5^+?OWs#eD?s
P9~nuv@DNnsMZW(6i7rTP

literal 0
HcmV?d00001

diff --git a/User_MicroService_Group3/app/controllers/__pycache__/loginController.cpython-311.pyc b/User_MicroService_Group3/app/controllers/__pycache__/loginController.cpython-311.pyc
index 0ae33a0fab843db2a609b147bf8a5d6eaea25f24..c0b17d9c4604c96ba994a28b64fd1eebc7061a71 100644
GIT binary patch
delta 66
zcmca7^+1YmIWI340}xE$_?IfjyOFPsjge<_FB>Z}qtoKaoJ@>Clc#Wh=Dz?`@qw9<
Vk?{i?1Ecwc$rE`LCU4<c1prbS6086K

delta 65
zcmaDLbx(?KIWI340}zxQ`H{MrXCq%78za}|UN%-{Mu)|dIhhy(CQsr1%ykZ^;sY}y
SBjb(9^LfN4Z{T4A;tc?SYZL_l

diff --git a/User_MicroService_Group3/app/controllers/__pycache__/logoutController.cpython-311.pyc b/User_MicroService_Group3/app/controllers/__pycache__/logoutController.cpython-311.pyc
index fef5e24b0dc447c671daa0656ba2d91c90e66b0a..63d12e36ae470889c341e2c26608db4c1b994b39 100644
GIT binary patch
delta 53
zcmX@Xahii~IWI340}$-y_?H^Zw2|*F6C=muH%wRg8-ao!m>C%vKd><{x-(9`z^pa-
HJ98iak@F8Q

delta 48
zcmX@jae{+yIWI340}#ZV`;q#CaU<VdCPuc&Z<wxf)d2-RFf%eT-k5xmS!ePu=0E^*
CeGkF_

diff --git a/User_MicroService_Group3/app/controllers/__pycache__/showReviewsController.cpython-311.pyc b/User_MicroService_Group3/app/controllers/__pycache__/showReviewsController.cpython-311.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..e94a298c93ec474867d52280eef3e0341f88aca2
GIT binary patch
literal 2018
zcmah}-ER{|5Z}EIf8cK?GR1%}HG~?8q@k#M6p(1Bf>aSu!$;-1Ivw7%bMg7k-8&~r
z>PS|F)U=9P9xCBVJmdjUD*C_+Z~Y_AktM8^kRnw)@a78jg{RJ4uw&DQPR=u%nc3Ny
zo!{(lk;ond^y)Awz2`^hFZZ85NpBagH(_xf5k#<#syL6ULSCqfd9f<xCG6@2U9S4_
zK5s4R{=8p66cdRC9tj9Nf!_}0gG44i;wOOzVtx;akv(^DK173?;l9VPBq0(m<3A#!
zF-Y_-dIWAy2Cn%C5$91Z{>s(lBp&=!uhSaS44eBGEz{6SE8NfMH+5=(#-f&`nMMxt
z$meRQqRyCxRj*Pu$3xbFx%>rP(&)0a8r99BsxO$9eeUdsXHW8^YgE{dRVg#GUgH6(
zGF^kHIguysn5J#nOsy#vWlNM<Jm7gL8sQ1GZkvi(Dp}Nq7{Fg)$hGLQKFP2U;rBWU
z+WW{JvJp{3_TUl`dWe6*Yq*Toga*EhzRs_S4RLW`-*lt=hlub9B0d>JU6btKuG6A>
zx<?J^9Y47tZ2J1vVcC#JJu$LlyY|LA=QU8pJA(-r8F=HX2Hp(pdhf1ATZ>UcfYwTL
zJYK9@wh4Xe_h417+ocm{a+t+ocP_{Py@*GOZ`-NBqQvDT6|lg4gceOgx#Yru%etu&
zi~H1CjT(fDIt5)(H!Yg;@sLrk_K)C!el!<99xk}Q3iwgWl*e{73Q=uUfyVRDkiv3r
zEaTCeXEWytHvtn?L9MP77Yf%5dYNfUv~bxh0`LsmDqIJvX{dVPrU3?KY4%FSEM?~F
zjM0_Cj9F(E&D=IwrErNXsYa2K%*=wSL*iv>Wi%smo8HOXpv48l)Xg#=(mPPOsuh_z
z4`|eiRGD=l`%wXkE<jZ_GhsXAG=%w?fqJsG!eei1?_UPXKuK<ctzUsP(TmstCw2+G
zXBT#4^GY`wZ_f67X#7AAh2^Bj*8SV*!w*h8Pfu>8Cm%1j)2BP>)9bN+d}#0fUlunH
zwNulb)bx4?wguxqM}Lgo`?ej(b^=)^kOil3Y<>BM^Bd<|pKOIDoX|u!oLK*?C!+AN
zUI59F@8`aoYfIxDY21;<w?oP1+-pb<ttO`GaN|=$#c}ESwfP$`_0T|j!6a7Eb?lQn
zGT!jDU@<y;i-VCNcogt!sDaqD-G3!v=i*@Wh*0qck{ui#vr%xbVLQ}M0HMY^(dQ8n
ziKJnW@MgL)=bz(#w=Q^6*!!@P9RS89qps^*ri__vHR&QPW0-aZfKUdUXhzP*Tr_gA
zOl{`QAouNDf!9&yrk@koQ4nlDFw4z5lVOKI@bK`f$Bu*Q1J~tCU`+(=iKR9wtz0{L
zq!T^ToZa?EdnhPRy$B^YF1BuMg|bd4`!aR3ojTS@9b2D$IhJmnZjWU<V_7Gh-5x*K
zT5`rFobbeUe6O?bgcF-|0+Z}81c#}Px+2QulCD}6=3cCqs#n2IL2|`?zrDF<<6!3j
zMKRPWRTLf@&Re-tV+nVE#&wcm4s7bx@;mYl^GbaaIA1kMU8fh>G`P7<xBdjy6EVhJ
z^s)1QUl$#6M!zl!HNC&><o<iP*44*n+R0O$<f&#1u$w;KjUVam%l7<ILg*o2%}6hr
y!ec!&%1$C7@f@eNaLU<x{OPTyR~(#b;|m>pp(jM}R1X3BTSUUe5sjzzs{0p0LjlzQ

literal 0
HcmV?d00001

diff --git a/User_MicroService_Group3/app/controllers/__pycache__/signupController.cpython-311.pyc b/User_MicroService_Group3/app/controllers/__pycache__/signupController.cpython-311.pyc
index d6315f975befa50cae416644dbce66638592358c..55cd6b76556ac83d7c5d814dc2a64f828492b907 100644
GIT binary patch
delta 192
zcmdlfvPgt?IWI340}$wP{!86Ikyny&)<ktn8778Q#uS!R&Sgvt46A_{0;0H5xfXCw
zPGl0DI8%e2Cxx?xA&Ph7iBM)X*3_b+{G!dOEGroqxi+6?Rc92HxgckHLD=j9kJ$qr
z;R$IMxMeS}$ZqClZ(?M$n%u{c&&W6VABWXsJ5C#M6QJ>oKwP{GNPJ*sWMurn#=vMY
kxu4T@@?B0XVYv?s+Kh4^nHiY$t}yC;U;=U`OL55q0M#Nd-T(jq

delta 243
zcmZ1^vQvb2IWI340}y!Fd`r!k$ScXXXrj8MN(w^?a}H+|Clf;|V+u<u*D@vshSfj}
z0a4tk+zWUnZ)6mmI8lS0H-)o>A&PI~fly`+_T1Fs;>7gS&C)C@85ub@A7xc%6qUQ6
zV17Z^;sTGw10K;CY!|rYFR;jOW@K+-WVD>z!jaF&KluxX6)Q_dZesFeT~1q3Q=m1B
zKwP{QNPJ*sWMsU-U_7~z)0OiE19t-$PCmw|Wu)+dL7P$GBQpb&-W5jO4@^MLhd4%F
OMz#+Om_(5Z&@cd@b2~u*

diff --git a/User_MicroService_Group3/app/controllers/__pycache__/updateProfileController.cpython-311.pyc b/User_MicroService_Group3/app/controllers/__pycache__/updateProfileController.cpython-311.pyc
index d12100ee3869119656505afbb8d537567f89b91e..8b7bc1569e5e102cdf2927d1001d7ef46f330135 100644
GIT binary patch
delta 1107
zcmZ`%O-vI(6rS1sY`g7lf3O8iB&$?#tpPNIXb~e3Fc?FSS`HP{)a(|U{*l=&Cbd`&
z95`qK?u8f*oT>&6B$~*PgHhwfk~Gn5Lc&20CLT(n7f#M>e?m>1y!qanZ@!)P=IwlT
zJZs@zvMdAe_|gwzZ|PO84Q{P=Unz({G$ySnCd@#9V^h+WvWM*uP(XsBSz?P60GoJL
zN0^hi4M%--+>5kmnT1={X1&NPfg+Y|Hl$&vXbS?t{*y3*Y4zj8fB-dTc20~ck{HR#
z5=uu?66QMQvJaAR`C)^L)J4*~lvY#^9D+~OAnY}+K-8%&!7Tj#<_LPBdfDJASVe2z
zIuFpTJjh!_V|$|jky)n}7^S5_fPWRuS6Hwqo?}|32=R6BtPThiYdr=aZ>{ILUM2C-
zHqo|jZ2l;SJB_DZWaCix9Pxr<LZiw3BXJS2>at;=;KZjO7Xdc`QZqV1fK;T>DM^;2
zvywm|BGl|@=~1Iuf-%R2^rrGbC8}g)%@V5hHb;|)A0NrFqok93?HtV{A(TOyF`Z2&
zbMBC={xXafEF>R!Imm`Vuvc?gtA(ax8O@0QT=f4{R+YNOPO4<|zZW5d##ZB6ewpm^
z$HvjS8v(Uw{Lpn4Z;(w{!Hr)8f6Tz)eVSMk_Bdae^DW*ypt(cPtv)yH6x_gjdZT^M
z<1c&s%VP(QwzaX6;|#Wg^A~r=KPAf}_e!T`u&prreBXBKj<9>X9JsT`PnG$p6?Wg*
z^D4LJ43wRLk~8q5wPV}68!t`Hl*jIu5~u>eP3kU%9UrRUApmXD)NdUz&$_0m3JaW_
zIAg`FJ~nqim-@myJlLvVRqoN<h!l&b<4Qb}mi5+ZCu?tALUK<c8cRect8X8#kxl(-
zK6i<<;59&9*dZT=Bg@rPM$9IqYp545$%B;NW2hJ)gcUP@L+UW?Q7370ZTdSwf2rBN
gfzeX4sX6+B&ky@50K=gHP=jR{s8DrAr}Y~C0{@>HP5=M^

delta 627
zcmeAbKE=<soR^o20SMf8{z_fNI+0I;amqw>%LFEdRK^sRRL*5g3=FG*7y_cWQn?mz
z!+6Ma3Tp~mI^!C4RP`wwEey+m%2vabM)9O@1~X`KO}r60IhoOxQDyQ%Mt!ED?~|`E
zmNM?x?8PL;Sf9lSQ(nWdj1j0Ch#{bsvqTieW?;aO<tl;e1j=&NFrd07m?4ETg)5U0
zOml;1O&-5n?4`x2Me&&_MIe9OVolARY|f%D%Ln8X@q-8f5FrR6gg}HakeGahB`l2%
z$hgItQkq*(T*LunYjPKXG~MEan3tE9e~Tq0u_O_vDNvOlHMjV(iu3d0!8*ZuKv7Z*
za?s>itXI_(fDCq!h$Jv18W_H^G4PA^WY5sN$ft6JPo=^A0XyFZ2Gz+^*>)I;Fvuy*
ziCV#VQP${+tWk#_P_3Ba0?CV_+E+xiJKUZMOU*D_V17|p`--sk1s?4WY?E)Y%Q5m!
z{=x1zxq?GQ4`kI!h9X5ERU{82esS33=BJeAq}ml}0J)%;D4qu-J}@&fGTxZ{kV9nh
j0}iXncAVNOnv4b?7=Xk_W(FqfD~whjm|!AcVX&D1pB;#s

diff --git a/User_MicroService_Group3/app/controllers/changePasswordController.py b/User_MicroService_Group3/app/controllers/changePasswordController.py
index 516ca01a..5fbb96db 100644
--- a/User_MicroService_Group3/app/controllers/changePasswordController.py
+++ b/User_MicroService_Group3/app/controllers/changePasswordController.py
@@ -1,3 +1,6 @@
+#This page allows users to change their password
+#
+#
 from flask import Blueprint, jsonify, request, session
 from models.changePassword import check_old_password, set_new_password
 import hashlib
@@ -9,9 +12,9 @@ change_password_bp = Blueprint("change_password",__name__)
 @change_password_bp.route("/user/change_password", methods=["POST"])
 def change_password():
 
-    user_id = session.get("user_id")
+    user_id = session.get("user_id") #Get user ID from session
 
-    if user_id:
+    if user_id:#checks if user is logges in
 
         if request.method == 'POST':
 
@@ -26,18 +29,17 @@ def change_password():
             new_password_salt = new_encoded_password["salt"]
             new_password_iterations = new_encoded_password["iterations"]
 
-            
+            #collect old password, user id and email into json
             old_auth = {
                 "user_id" : user_id,
                 "email" : email,
                 "password": old_password
             }
 
-            #user_old_auth = check_old_password(old_auth) #Collect user data from database
+            #user_old_auth = check_old_password(old_auth) 
             
 
-
-                
+            #send old password to database            
             old_auth_info, value = check_old_password(old_auth) #function returns certain columns collected from database
 
             if value == 1: #if user exists in database
@@ -47,12 +49,13 @@ def change_password():
                 old_password_iterations = old_auth_info.get("Iterations")
 
 
-                #password authentication
+                #password authentication. Calls password fucntions
                 old_password_info = generate_password_hash(old_password)
                 is_correct = verify_password(old_password_info, old_password, old_password_salt, old_password_iterations, old_password_hash)
 
-                if is_correct == True:
+                if is_correct == True:#if password is correct
 
+                    #passes new password information to json
                     new_auth = {
                         "user_id" : user_id,
                         "email" : email,
@@ -62,6 +65,7 @@ def change_password():
                         "iterations": new_password_iterations
                     }
 
+                    #sends new password to database
                     new_auth_info = set_new_password(new_auth)
 
 
@@ -86,7 +90,7 @@ def change_password():
 
     
 
-
+#password encoding
 def generate_password_hash(password):
     # Generate a 16-byte salt
     salt = secrets.token_bytes(16)
@@ -103,6 +107,7 @@ def generate_password_hash(password):
     }
 
 
+#password verification
 def verify_password(stored_password_info, submitted_password, salt, iterations, user_hash):
     # Convert the stored salt back to bytes
     salt = bytes.fromhex(salt)
diff --git a/User_MicroService_Group3/app/controllers/deleteProfileController.py b/User_MicroService_Group3/app/controllers/deleteProfileController.py
index c74dfe1f..f29f3689 100644
--- a/User_MicroService_Group3/app/controllers/deleteProfileController.py
+++ b/User_MicroService_Group3/app/controllers/deleteProfileController.py
@@ -1,3 +1,6 @@
+#This section allows a user to delete their profile
+#
+
 from flask import Blueprint, jsonify, request, session
 from models.deleteProfile import delete
 
@@ -6,9 +9,10 @@ deleteProfile_bp = Blueprint("deleteProfile",__name__)
 @deleteProfile_bp.route("/user/deleteProfile", methods=["POST"])
 def deleteProfile():
 
+    #collects user id from session
     user_id = session.get("user_id")
 
-    if user_id:
+    if user_id:#checks if user is logged in
 
         if request.method == 'POST':
 
@@ -21,7 +25,7 @@ def deleteProfile():
                 "user_id" : user_id
             }
 
-            user = delete(user_info) #Collect user data from database
+            user = delete(user_info) #sends user data to database
             
 
             return jsonify(user, user_id)
diff --git a/User_MicroService_Group3/app/controllers/fetchUsernameController.py b/User_MicroService_Group3/app/controllers/fetchUsernameController.py
new file mode 100644
index 00000000..311efa0a
--- /dev/null
+++ b/User_MicroService_Group3/app/controllers/fetchUsernameController.py
@@ -0,0 +1,28 @@
+from flask import Blueprint, jsonify, request, json, session
+from models.fetchUsername import get_username
+
+fetch_username_bp = Blueprint("getUsername",__name__)
+
+@fetch_username_bp.route("/user/getUsername", methods=["POST"])
+def username():
+
+    user_id = session.get("user_id") #gets session data
+
+    #if user_id: #if user is logged in
+
+    if request.method == 'POST':
+
+        #User data from front end
+        data = request.get_json()
+        userID = data.get("id")
+
+            
+
+        username= get_username(userID) #Send user info to database
+
+        return jsonify({"username" : username}), 200
+    
+    else:
+        return {"error" : "null"}
+    #else:
+     #   return {"error" : "User not logged in"}
\ No newline at end of file
diff --git a/User_MicroService_Group3/app/controllers/getUsersController.py b/User_MicroService_Group3/app/controllers/getUsersController.py
new file mode 100644
index 00000000..8c51a05f
--- /dev/null
+++ b/User_MicroService_Group3/app/controllers/getUsersController.py
@@ -0,0 +1,18 @@
+from flask import Blueprint, jsonify, request, json, session, redirect
+
+from models.getUsers import fetch_user_info
+
+from kafka import KafkaConsumer
+
+consumer = KafkaConsumer("review_events", bootstrap_servers='localhost:9092')
+
+def getusers(user_id):
+
+    pass
+
+
+for message in consumer:
+
+    event_data = json.loads(message.value.decode())
+    user_id = event_data['user_id']
+    username = getusers(user_id)
\ No newline at end of file
diff --git a/User_MicroService_Group3/app/controllers/loginController.py b/User_MicroService_Group3/app/controllers/loginController.py
index 31313b3f..232350cd 100644
--- a/User_MicroService_Group3/app/controllers/loginController.py
+++ b/User_MicroService_Group3/app/controllers/loginController.py
@@ -1,3 +1,5 @@
+#This section allows a user to log in
+
 from flask import Blueprint, jsonify, request, session
 from models.login import fetch_user
 from models.login import fetch_password
@@ -40,7 +42,7 @@ def login():
                 password_info = generate_password_hash(password)
                 is_correct = verify_password(password_info, password, user_salt, user_iterations, user_hash)
 
-                if is_correct == True:
+                if is_correct == True: #if password is correct
                     session["user_id"] = user.get("UserID")
                     response_data = {"message":"Login Sucessful", "email": email, "session" : session["user_id"]}
                     return jsonify(response_data)
@@ -60,7 +62,7 @@ def login():
     return {"message" : "null"}
     
 
-
+#password encryption
 def generate_password_hash(password):
     # Generate a 16-byte salt
     salt = secrets.token_bytes(16)
@@ -76,7 +78,7 @@ def generate_password_hash(password):
         'hash': hash.hex()
     }
 
-
+#password verification
 def verify_password(stored_password_info, submitted_password, salt, iterations, user_hash):
     # Convert the stored salt back to bytes
     salt = bytes.fromhex(salt)
diff --git a/User_MicroService_Group3/app/controllers/logoutController.py b/User_MicroService_Group3/app/controllers/logoutController.py
index c7ff97bc..241e00d3 100644
--- a/User_MicroService_Group3/app/controllers/logoutController.py
+++ b/User_MicroService_Group3/app/controllers/logoutController.py
@@ -1,3 +1,5 @@
+#This section allows a user to log out
+
 from flask import Blueprint, jsonify, request, json, session, redirect
 
 
@@ -6,13 +8,13 @@ logout_bp = Blueprint("logout",__name__)
 @logout_bp.route("/logout", methods=["POST"])
 def logout():
 
-    user_id = session.get("user_id")
+    user_id = session.get("user_id") #get session data
 
-    if user_id:
+    if user_id: #if user is logges in
 
         if request.method == 'POST':
 
-            session.pop("user_id", None)
+            session.pop("user_id", None) #deletes session
             return ({"message" : "Log out successful"})
         
         else:
diff --git a/User_MicroService_Group3/app/controllers/showReviewsController.py b/User_MicroService_Group3/app/controllers/showReviewsController.py
new file mode 100644
index 00000000..8ac832b3
--- /dev/null
+++ b/User_MicroService_Group3/app/controllers/showReviewsController.py
@@ -0,0 +1,54 @@
+from flask import Blueprint, jsonify, request, session
+from kafka import KafkaConsumer
+import json
+
+show_reviews_bp = Blueprint("showReviews", __name__)
+
+# Kafka consumer configuration
+consumer_conf = {
+    "bootstrap_servers": "localhost:9092",
+    "group_id": "show_reviews_group",  # Specify a unique group ID for this consumer
+    "auto_offset_reset": "earliest"    # Start consuming from the beginning of the topic
+}
+
+# Function to consume reviews from Kafka
+def consume_reviews(num_reviews=1):
+    consumer = KafkaConsumer("customer_reviews", **consumer_conf)
+    reviews = []
+    
+    # Iterate over messages received by the consumer
+    for message in consumer:
+        # Decode the message from bytes to a string using UTF-8 encoding
+        review_data_str = message.value.decode("utf-8")
+        
+        # Parse the JSON-encoded message to extract the review data
+        review_data = json.loads(review_data_str)
+        
+        # Append the review data to the list of reviews
+        reviews.append(review_data)
+        
+        # Exit the loop after consuming the specified number of reviews
+        if len(reviews) >= num_reviews:
+            break
+
+    # Close the consumer to release resources
+    consumer.close()
+
+    return reviews
+
+# Route to show reviews for a user
+@show_reviews_bp.route("/user/showReviews", methods=["POST"])
+def show_reviews():
+    # Collect user id from session
+    user_id = session.get("user_id")
+
+    if user_id:  # Check if user is logged in
+        if request.method == 'POST':
+            # Call function to consume reviews
+            reviews = consume_reviews()
+
+            return jsonify(reviews)
+        else:
+            return {"message": "null"}
+    else:
+        return {"error": "User not logged in"}
diff --git a/User_MicroService_Group3/app/controllers/signupController.py b/User_MicroService_Group3/app/controllers/signupController.py
index 3876e7a8..0ec06637 100644
--- a/User_MicroService_Group3/app/controllers/signupController.py
+++ b/User_MicroService_Group3/app/controllers/signupController.py
@@ -1,8 +1,9 @@
+#This section allows a user to create a profile
+
 from flask import Blueprint, jsonify, request, json
 from models.signup import new_user
 import hashlib
 import secrets
-import hmac
 
 signup_bp = Blueprint("signup",__name__)
 
@@ -24,7 +25,7 @@ def signup():
         salt = encoded_password["salt"]
         iterations = encoded_password["iterations"]
 
-        if email.strip() != "":
+        if email.strip() != "": #checks if email is not empty (email cannot be null)
             
             # Create a dictionary from user data
             user_data = {
@@ -48,9 +49,9 @@ def signup():
             return jsonify(update)
         
         else:
-            return {"message" : "email cannot be empty"}
+            return {"error" : "email cannot be empty"}
     
-    return {"message" : "null"}
+    return {"error" : "null"}
     
 
 #This function encrypts the user's password
diff --git a/User_MicroService_Group3/app/controllers/updateProfileController.py b/User_MicroService_Group3/app/controllers/updateProfileController.py
index faedd619..bca31198 100644
--- a/User_MicroService_Group3/app/controllers/updateProfileController.py
+++ b/User_MicroService_Group3/app/controllers/updateProfileController.py
@@ -1,15 +1,20 @@
+#This section allows a user to update their profile
+
 from flask import Blueprint, jsonify, request, json, session
 from models.updateProfile import update_user
 from models.updateProfile import fetch_user_info
 
+from events.eventDefinitions import updated_username
+from publishers.kafkaPublishers import publish_username_updated_event
+
 update_profile_bp = Blueprint("update",__name__)
 
 @update_profile_bp.route("/user/update", methods=["POST"])
 def update_profile():
 
-    user_id = session.get("user_id")
+    user_id = session.get("user_id") #gets session data
 
-    if user_id:
+    if user_id: #if user is logged in
 
         user_info = fetch_user_info(user_id)
         print(jsonify(user_info))
@@ -25,7 +30,7 @@ def update_profile():
             gender = data.get("gender")
 
                 
-            # Create a dictionary from user data
+            # Create a json object from user data
             user_data = {
                 "user_id" : user_id,
                 "email": email,
@@ -35,13 +40,15 @@ def update_profile():
                 "gender": gender,
             }
 
-            # Convert to JSON
-            json_user_data = json.dumps(user_data)
+            update = update_user(user_data) #Send user info to database
 
+            if "message" in update:
 
-            update = update_user(user_data) #Send user info to database
+                event_data = {"user_id" : user_id, "new_username" : user_data["first_name"]}
+                event_message = updated_username(user_id, user_data["first_name"])
+                publish_username_updated_event(event_data)
 
-            return jsonify(update, user_id)
+                return jsonify({"Update Status": update, "Username" : user_data["first_name"], "User ID" : user_id, "Event message" : event_message})
         
         else:
             return {"error" : "null"}
diff --git a/User_MicroService_Group3/app/events/__init__.py b/User_MicroService_Group3/app/events/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/User_MicroService_Group3/app/events/__pycache__/__init__.cpython-311.pyc b/User_MicroService_Group3/app/events/__pycache__/__init__.cpython-311.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..95be18671d60d24a8dd5c89660bea97b034080d2
GIT binary patch
literal 272
zcmXv}yJ`b55R_sPLcrt~)TT+3R3RA58B*l|7vp9@D7v*zM5jGgr-S>Fd_anj@5&Dt
z+_{R**i+2T?i4foGo4<EjQU=z$N4wX3Gyg*7g>CXN|fS8zWfS4%lmFL_us_>EF*FR
z(+swT*MJLlJ;H))YA|#W-m*)<cvyyPaCF_EXsyb`i~|&uIHFn+f5N=#O|V$0qBh=R
z*kDvHs1<&wceHgNPaB8v5U8J>Wh#+-XHh>frS=X?+XD87RIOcboz}PQu)ln4s7fAZ
We4aaxU&ZT8+liEND^A3deESD5ZcuFi

literal 0
HcmV?d00001

diff --git a/User_MicroService_Group3/app/events/__pycache__/eventDefinitions.cpython-311.pyc b/User_MicroService_Group3/app/events/__pycache__/eventDefinitions.cpython-311.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..26189d001a07adbc3c51f25578fd46235d1830b5
GIT binary patch
literal 492
zcmZWmJ4*vW5Z=8r#z%aBjiit*L<oW?b|Qi#VC4g%2(oaTw-d8?**#|OA_o>0{s$Wi
zI}!hoTqXDi0_m)rJ0Fb;^UVzN?Kgb8&vSD#jLz03>pfBaD4XBIe~NK~iU+3HJ-c9v
zcUjAeyk8RK2@0QLJWoJ8e#>sT@*aI+`bWh=g0`n)2(m<lDX5lT%)k&#8l-swMLlzX
zfmTJsz)es#CLF*EEx{V;;Us}8*9r0Y+TM|8#Beek<WXN98|a`Og6!BR8<3=vCp5Jt
zjOCf30Xm)L!uCWrLxfzmZH5lSxy5U_uZE$CK#6ugjAJlY;Dk2f94^HvM15mpd!@lu
z3xh))q3r?=bp*iy+AP_YVUozoi2F_*=xL)<ZH?PV@?!DF@1G}}CKu(Sx+cLLdvC74
zEj8bkS4TCku{L7gP+J?*lpVEr#m71|Sbh>t5qwVV4y?*z*uz<BE439WMn30!<V|qW
I`483oFLtem;{X5v

literal 0
HcmV?d00001

diff --git a/User_MicroService_Group3/app/events/eventDefinitions.py b/User_MicroService_Group3/app/events/eventDefinitions.py
new file mode 100644
index 00000000..bb880664
--- /dev/null
+++ b/User_MicroService_Group3/app/events/eventDefinitions.py
@@ -0,0 +1,5 @@
+def updated_username(user_id, new_username):
+
+    return {"event_type": "profile_updated",
+        "user_id": user_id,
+        "new_username": new_username}
\ No newline at end of file
diff --git a/User_MicroService_Group3/app/index.py b/User_MicroService_Group3/app/index.py
index 32fd79e7..a22a9736 100644
--- a/User_MicroService_Group3/app/index.py
+++ b/User_MicroService_Group3/app/index.py
@@ -1,4 +1,4 @@
-from flask import Flask, redirect, url_for, request, render_template, make_response, session, abort
+from flask import Flask, jsonify, redirect, json, url_for, request, render_template, make_response, session, abort
 from flask_cors import CORS
 from flask import jsonify
 from controllers.loginController import login_bp
@@ -7,13 +7,20 @@ from controllers.updateProfileController import update_profile_bp
 from controllers.changePasswordController import change_password_bp
 from controllers.deleteProfileController import deleteProfile_bp
 from controllers.logoutController import logout_bp
+from controllers.fetchUsernameController import fetch_username_bp
+from controllers.showReviewsController import show_reviews_bp
+
+from config import DEBUG, SECRET_KEY, PORT
+import os
+import requests
+import publishers
 
 
 
 app = Flask(__name__)
 CORS(app)
 
-app.secret_key = 'Group3'
+app.secret_key = SECRET_KEY
 
 @app.route('/')
 def index():
@@ -37,6 +44,21 @@ app.register_blueprint(deleteProfile_bp)
 
 app.register_blueprint(logout_bp)
 
+app.register_blueprint(fetch_username_bp)
+
+app.register_blueprint(show_reviews_bp)
+
+publishers.create_profile_updated_topic()
+
+
+
+
+@app.route("/userIDs", methods=["POST"])
+def userIDs():
+
+    #ids = request.json
+    #print(ids)
+    return 'hi'
 
 if __name__ == '__main__':
-    app.run(debug=True, port=5000)
\ No newline at end of file
+    app.run(debug=DEBUG, port=PORT)
\ No newline at end of file
diff --git a/User_MicroService_Group3/app/models/__pycache__/changePassword.cpython-311.pyc b/User_MicroService_Group3/app/models/__pycache__/changePassword.cpython-311.pyc
index 3e2f696425d98b4acece898d09560e3b644ec81a..efbc1602a81cf43627230b17ff6be9b650f9cba8 100644
GIT binary patch
delta 23
dcmdn2y;+-YIWI340}zOE{Y&-Y*~qt46aYsU1?K<&

delta 23
dcmdn2y;+-YIWI340}!mc_9OKY_eQ>@q5xMp2h9Kg

diff --git a/User_MicroService_Group3/app/models/__pycache__/fetchUsername.cpython-311.pyc b/User_MicroService_Group3/app/models/__pycache__/fetchUsername.cpython-311.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..ae95206848ec046c1557589c2b224c793de637e2
GIT binary patch
literal 2209
zcmd5-U1-}@6uy!yM{#UtcJtGuC02e44Rje}-4;r=;Uvx&Nz*Ymlm>xOq?<&otm|IM
zaU7gc#vZ&-NC$-u#-LBxMqc{3=QZuKT?{pXL164*Z-P(=ec8@+Vkc?(kgyGQb#-*^
z`TNefKe|7LLIDKr+2mjNnSjvmY*26fKC^QPn1@J5I%lFZH_LI1=S_Z=hp%7?Y2U05
zWWKM_tf=!zG${VbTn9O~>6T3_V?I9(d_W_Xg*7Lo&uQF#X!a4|1!%N$8R$dQjGRN-
z4Nz>tyVq8^0{7^Uwk}8LH9KDCR)qrps9wT>A#equfHpw0+0b$bY*`M++G}xr1s{FC
z;M4i8hGl`LZQ$)|2o5nvy#a-z?NGsqY?CMnb8*V(9Vd;hLv;4`BPV!}@U5mgKY-}u
zs^~=OV+0Fb5Wh!1@Eb7yn~gQ#&`pT5Dt;;c*O~62<TxjKkkcEo^!-1w%%NrBCdzUB
zr(MAl?~fd+V+@MZE0>drsl?cIdB(=nQqx$T_~P1CS)U_AOp<ccITOpdMNDzc<g;=4
zBl#1`4!}zPxC(03#xkaqP}#8LdF*J5sVws}ta)-pUU_@Q!pj*ry;$EjBbt__FnW{u
zV1Tkc?)t&RCe&@h%UH`g*p+ILiG^KJGl>lX2Er0{{h2(0KZ7eKSQf6Bp@!wS&530V
zXB>lAgMODc^u}KVB-GC^#5-9`^R7Ti&gHPpWOA*&`f2Qn!m76wHJ#TMm1`Crr^XUi
z#)+0qW6QCX&p}Hp)l_CIP*B@&@-ms1lUYh}UKt~hK9+9~dRvL>ORA+oy<>~2X<};u
z+pP2(cuu~KwMC1VWWm684KQ`p&?re_x@2fL^(iIU%zKKO$tY=}W7Ae@lfW`#g%4%&
zZg2rRwdrO8+72bKGVBPf&t2sCVq)x%_Sm<|1Em<KM$Wy6^gWOCl_LX{$UxD*{nkWL
ztV-ea@LKqO_Pe>V)LW5yOH%K4xNV)Rk#aaz3CD`Uc1zepLi5?`nU4E+9(>^Sp<vWQ
zT=ThVFuFdqHucT)z3Jj~wWXa2W7S~Ci{Sa^!Sm%{PbJt>s&!8Qjn|Lb&U!tk_l6jI
z0a*Oqmz@yd-iU{IvF(8TCWT7j4<E;YKrc(f6=}F64Od&w6dm?>;eU#|ySw|c6$PQn
z<G}G>)KVC*<7H{IB8`@$(F0)rzX0sD0wyG|>jh39tu}YyYmdOz_$uBxI*fiDZcSVe
zo-{?rL&B3TU*aO#3WY$j)g4X9!qz1wc`Az_d3r%${Ka=BIt4gL;=HNaw<){vXbTXx
zdv9kB>HEKe)c#$~P8mDNwLSSW+5r~PHXyI05pc<x_+#1)Lv|n7lRzL#j;o@s($QW;
Yp}V!Giry_9?Vi7vi+Sicq3n+R8=}_$z5oCK

literal 0
HcmV?d00001

diff --git a/User_MicroService_Group3/app/models/__pycache__/getUsers.cpython-311.pyc b/User_MicroService_Group3/app/models/__pycache__/getUsers.cpython-311.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..dd54bdac2b3189ffb26e70c80dcb6d7a9d4b3f61
GIT binary patch
literal 272
zcmXv}%Sr=55S&R+f)M<Lxq9*9Ed)U};K>K9A(w_Q&bGUQv(rn@&f<QFAK*d6&+-QX
zxrH2@4M`oUtE&!O{XLyth=kvdJr474pcCX#Y|oSU6otsem3;gWJWBg^2zOuE43+^o
zfUbK}!IQ@Y+YVttCf4ZN0M98UuN^FX3OLxdSM;Xx$c#N?6gi+;5x>J-(P?k6P+6s&
zLtkQ0)~gl1suwhsCr72la5%Vru!bo|?ySM}JyUFMKsOE4RG<q`VteRy-SoT3Jekqq
WEuW>%!&l)l(Pk{A+=vtLIC=lS98v%P

literal 0
HcmV?d00001

diff --git a/User_MicroService_Group3/app/models/__pycache__/updateProfile.cpython-311.pyc b/User_MicroService_Group3/app/models/__pycache__/updateProfile.cpython-311.pyc
index 43ec1e62b7e96678f2be3c7811088ea64c8e1774..a3cc094c4a2bb3f0c99ed37c439242aab85aaf1a 100644
GIT binary patch
delta 20
acmeBG?p5Yq&dbZi00dede>QSA2?78y`ULa<

delta 20
acmeBG?p5Yq&dbZi00ezIe{JM$5(EG@QU%8V

diff --git a/User_MicroService_Group3/app/models/changePassword.py b/User_MicroService_Group3/app/models/changePassword.py
index 18d40df2..7cb162b6 100644
--- a/User_MicroService_Group3/app/models/changePassword.py
+++ b/User_MicroService_Group3/app/models/changePassword.py
@@ -18,17 +18,17 @@ def check_old_password(data):
 
         # Check if the email already exists
         email_check_query = "SELECT COUNT(*) FROM dbo.User_table WHERE UserID = ?"
-        cursor.execute(email_check_query, user_id)
+        cursor.execute(email_check_query, user_id) #executes the query
         count = cursor.fetchone()[0]
 
         if count == 0:
             return ({"Error" : "Email does not exist"}, 0)
         
         else:
-
+            #selects password information from database
             query = "SELECT t1.Email, t1.UserID, t2.Iterations, t2.PasswordHash, t2.PasswordSalt FROM dbo.User_table as t1 INNER JOIN dbo.AuthInfo as t2 ON t1.UserID = t2.UserID where t1.UserID= ?"
             
-            cursor.execute(query, user_id)
+            cursor.execute(query, user_id) #executes query
 
             row = cursor.fetchone()
 
@@ -67,13 +67,13 @@ def set_new_password(data):
         user_id = data["user_id"]
         
 
-        # 
+        #selects user ID
         select_userID_query = "SELECT UserID from dbo.User_table where UserID = ?"
         cursor.execute(select_userID_query, user_id)
         UserID = cursor.fetchone()[0]
 
 
-        # 
+        #updates password
         update_authinfo_query = '''UPDATE dbo.AuthInfo
     SET PasswordHash = ?, PasswordSalt = ?, Iterations = ?, TempPlainText = ?
     WHERE UserID = ?'''
diff --git a/User_MicroService_Group3/app/models/fetchUsername.py b/User_MicroService_Group3/app/models/fetchUsername.py
new file mode 100644
index 00000000..437cac41
--- /dev/null
+++ b/User_MicroService_Group3/app/models/fetchUsername.py
@@ -0,0 +1,39 @@
+from flask import jsonify
+import pyodbc
+from models.database_connection import connect_db
+
+
+def get_username(id):
+
+    try: #error handling
+
+        connection = connect_db()
+        cursor = connection.cursor()
+
+        query = "SELECT Username FROM dbo.User_table where UserID = ?"
+        cursor.execute(query, id)
+
+        row = cursor.fetchone() #fetch data
+
+        if row:
+            return row[0]  # Assuming the username is in the first column
+        else:
+            return None
+
+        #connection.close()
+
+        return username
+    
+    except pyodbc.Error as e: #error handling
+        print(f"Database error in fetch_user_info: {e}")
+        return None
+    
+    except Exception as e: #error handling
+        print(f"Unexpected error occured in fetch_user_info: {e}")
+        return None
+    
+    finally:
+        if cursor:
+            cursor.close()
+        if connection:
+            connection.close()
diff --git a/User_MicroService_Group3/app/models/getUsers.py b/User_MicroService_Group3/app/models/getUsers.py
new file mode 100644
index 00000000..f056e2de
--- /dev/null
+++ b/User_MicroService_Group3/app/models/getUsers.py
@@ -0,0 +1,38 @@
+#from app import db
+from flask import jsonify
+import pyodbc
+from models.database_connection import connect_db
+
+
+def fetch_user_info(id):
+
+    try: #error handling
+
+        connection = connect_db()
+        cursor = connection.cursor()
+
+        query = "SELECT First_name, Last_name FROM dbo.User_table where UserID = ?"
+        cursor.execute(query, id)
+
+        row = cursor.fetchone() #fetch data
+
+        columns = [column[0] for column in cursor.description]
+        user_data = dict(zip(columns, row))
+
+        #connection.close()
+
+        return user_data
+    
+    except pyodbc.Error as e: #error handling
+        print(f"Database error in fetch_user_info: {e}")
+        return None
+    
+    except Exception as e: #error handling
+        print(f"Unexpected error occured in fetch_user_info: {e}")
+        return None
+    
+    finally:
+        if cursor:
+            cursor.close()
+        if connection:
+            connection.close()
\ No newline at end of file
diff --git a/User_MicroService_Group3/app/publishers/__init__.py b/User_MicroService_Group3/app/publishers/__init__.py
new file mode 100644
index 00000000..beb65e5e
--- /dev/null
+++ b/User_MicroService_Group3/app/publishers/__init__.py
@@ -0,0 +1 @@
+from publishers.kafkaPublishers import create_profile_updated_topic
\ No newline at end of file
diff --git a/User_MicroService_Group3/app/publishers/__pycache__/__init__.cpython-311.pyc b/User_MicroService_Group3/app/publishers/__pycache__/__init__.cpython-311.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..3e5ad7960c3085c3269be00737e82ddc12a6c966
GIT binary patch
literal 369
zcmZurO-lnY5KUT?BJ|=>6!yB8Uc8A2vIS3Sp_YOKLYmBWL$gVkYzq4W{0;tu;=l1I
zy?XMd^wyK9_;GQVkN23z%v<&Q2PDPA$6i^a`MM)N(fJ0O!vr3QB8nPP(|byZ>WoR=
zecK6gx;~Z&q5<yFmD&K0UL~q{<GhwPd1rm(<ILz#0fxaslnXKX<=9O(p2%i*YP%}V
z*d!zs6Ll*qc57jXdI@akWURq9fsNAESz*}3rUeGww3#cjaYTfc6)s|cZ0c~qF4a<4
z2`VcpVGP(ggiPCP3bX7EWM!Rka}D9^A-~oV-57AGCGabB(VsHmJ^M4xIM-G;oDY1v
f?VZ<7MFSVuOTKBUaFW`4ms0vdis%0l_mkoi7pZkz

literal 0
HcmV?d00001

diff --git a/User_MicroService_Group3/app/publishers/__pycache__/kafkaPublishers.cpython-311.pyc b/User_MicroService_Group3/app/publishers/__pycache__/kafkaPublishers.cpython-311.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..3847106fe73d1b4414eb89e2fd3d5401f6c225f7
GIT binary patch
literal 2334
zcma)7O>7fK6rT0&+G9HogxCRG1SX)Sc1VJtjUY{`&`=`L;)Di-Fjn1VcbqI)?^?6#
zq>1dxYAZFzs;WeeoG6H>>apsnrI#Mp(MpL{LPDx?;Fc<fB2Im?{z)9D)VH&5XWqP-
z_vX!e-~Jehgb<MPkC^ZABlH&=G>LC?cGA$fj})YE8Y*xZj$?hF<}2_Sz93`-Z_I0A
zM)V=VDZ-lgkVEJRymiX>75_IV6Ho%cvBJ-wB!0oBlAIg)Sjx{!)6`H(GNDPId(abH
zQVOa*p{Yc-T%0D0H;kexr(bnyhAe4whG~slJbUrnW6tfmYZ#VkQK^_S30)x6lp9vP
zj|iNdW9L_3_mS1|3BhUBeC>W#kiu8M|B4S@zKkC1(e`%p*hAn?TEmJ^=E}kXN6%Qy
zR)aw1EAtQsu>GVNM^q7E&(^4^%f4lCmQ(y|frmcOhqq2Ft~1`7#AyoGgJ=Ml8!J*H
zuWBS$Dk_pil$^z)^MZMs<Xu6R3dHTyONCrfqLyl@hHkotC@E^HEU{58FUgicuRydz
zI$5kQH{HmBq^WGfoS|z=Nr4K?SXfg{tD!>K5#5MP3Dfednn}OgA+g)a$@S|BdGZ|d
zf<{1}cCtmCb!mZE5}1(O;I3hIu!KjiewrA`-h_KJvr=J6p36?@<T6zkNcOTJmkN*!
zW_B884PDZ*H+7hxrfMxEjC^9IL@8OyP8cO>lEf{8&Sx(v3z9AqB{4B4X&TXIiJ4IK
z#4U0+af8Tnx}h1fDlt8SxofISjTy)wRVKMfYLtrSvr@5`Etc*=0OpuW^IoR5#)HKr
z_gEtoZ@dtC1P;c^%lsNx6>W8&vWKtO-IKNMNvC_V`pLE*9ZFWOZpM15>CK~YTj&8v
zPwz%-U_CZaiw!xkp=ugL_|WQcJJ1JhD|+lf>X*;#&#4_XYf;mQnk&KQIJ$v**KzNo
zrAPCB#%$bM!&45PvYTx?i10hGdI#J<^4_Fop=SxXvkB7n^0?R1E2Dj7!dWac8uaFb
zR=6_vV2@T)8_I59(XH|ANnh~=QQ7xkPciLT`x>-Vc#Gv&gA{+eryOdV4V3wNtbjaf
zx4KUggC_o8nnBPE{+FiScM4h2<}5;|5sg=bHlIReVZSH0q2w#Vmx7M#-$iZ_eZk*G
zi|ug_@9w+XYX_$~fF#3d%F=LIELr)13jn$zRC<ZLU_uxLEVV$4lC>PaMod$hB?%KM
zEn${q8OHgNrY)UZ_TOL_GqN0-Zeq&Fa$qW-H;FZ}eE5n4aHJ$GgDq7Oh59}t$qrYz
z2i59|N~usZT?}>N;k+v_J=afk*-(hf&l1ZOi&O=)7d@bGgDvcG{f1}84Sw{6Oo|M^
zTrsbe%(<lKhR6c=n)4u~(f15?FbN<O{1m{>0ZL?pD!CT=aKvN@=7A193_bUFqtJ6D
zfFFikEpYWL&>>Jd0k8QtFsS9O*bnj5tF^8^r>n1eb*uZW`(xja*(Wdj7TOrUzCM24
z{`7WjJmZXKz8kA`-*LL{K)L$@;+f6(+Z*xJdOY>>IXj-J#fP2v@XCQ_IAV9EYPjFQ
z{Wk80;mX|V0q4j-4G%ha(8hyIq^(Xl$KI>qVFwS}c$kUQ)f3Lqp&CBx;Ip>ZUOo#)
zw-G0v*=64DeUG|Y`-6$S?IqAQ4@=;?C3Jk7{wiG)qK*)?o6S55r~X~Mbo#>-dYTGN
zbn;K%Jvb5M{|JiEPX=Al14qiR#0`7>LGP#F{X@Lp20adQG{G3dMK7R_5oH^DH}DFN
z79cq^@&P>$GKN0p0x)ol<2KO=yS;6qbM~9sa}=(6&-3t+l`*^jeLFl_3y(VC(JJ1?
UUEDOcjrQ<Vgo|yX*O}+nzbA27T>t<8

literal 0
HcmV?d00001

diff --git a/User_MicroService_Group3/app/publishers/kafkaPublishers.py b/User_MicroService_Group3/app/publishers/kafkaPublishers.py
new file mode 100644
index 00000000..042a5c13
--- /dev/null
+++ b/User_MicroService_Group3/app/publishers/kafkaPublishers.py
@@ -0,0 +1,44 @@
+from kafka import KafkaProducer
+from kafka.admin import KafkaAdminClient, NewTopic
+
+import json
+
+producer = KafkaProducer(bootstrap_servers="localhost:9092")
+
+
+
+def create_profile_updated_topic():
+    # Create KafkaAdminClient instance
+    admin_client = KafkaAdminClient(bootstrap_servers="localhost:9092")
+
+    # Define the topic name and configuration
+    topic_name = "profile_updated_topic"
+    num_partitions = 1
+    replication_factor = 1
+
+    # Retrieve the list of existing topics
+    topic_metadata = admin_client.list_topics()
+
+    # Check if the topic already exists
+    if topic_name not in topic_metadata:
+        # Define the configuration for the new topic
+        new_topic = NewTopic(name=topic_name, num_partitions=num_partitions, replication_factor=replication_factor)
+        # Create the new topic
+        admin_client.create_topics(new_topics=[new_topic], validate_only=False)
+
+
+
+def publish_username_updated_event(event_data):
+    # Serialize the event data to JSON
+    event_json = json.dumps(event_data)
+    # Publish the event to the Kafka topic
+    data_to_send = producer.send("profile_updated_topic", value=event_json.encode("utf-8"))
+    try:
+        record_metadata = data_to_send.get(timeout=10)
+        print("Message sent successfully!")
+        print("Topic:", record_metadata.topic)
+        print("Partition:", record_metadata.partition)
+        print("Offset:", record_metadata.offset)
+    except Exception as e:
+        print("Failed to send message:", e)
+    producer.flush()
\ No newline at end of file
-- 
GitLab