@@ -17,7 +17,7 @@ class ClickStatsData(BaseModel):
17
17
18
18
class UrlRequest (BaseModel ):
19
19
url : str
20
- # Frontend-provided hostname of this service (no port)
20
+ # Frontend-provided hostname of this service
21
21
service_host : str
22
22
23
23
class ClickStats (BaseModel ):
@@ -34,96 +34,35 @@ class ClickStats(BaseModel):
34
34
click_stats : Dict [str , ClickStatsData ] = {}
35
35
36
36
def generate_short_code (length : int = 6 ) -> str :
37
- return '' .join (random .choices (string .ascii_letters + string .digits , k = length ))
38
-
39
- def is_self_referencing (url : str , service_host : Optional [str ]) -> bool :
40
- """Check if URL points to the same service hostname (ports ignored).
41
-
42
- Compares the target URL's hostname with the provided `service_host`.
43
- Hostname comparison is case-insensitive; port is ignored.
44
- """
45
- try :
46
- # Add protocol if missing so urlparse can extract netloc/port
47
- if not url .startswith (("http://" , "https://" )):
48
- url = "http://" + url
49
-
50
- parsed = urlparse (url )
51
-
52
- # Extract target hostname (lower-cased)
53
- target_host = (parsed .hostname or "" ).lower ()
54
-
55
- # Determine service hostname (lower-cased). Frontend should send hostname only.
56
- service_hostname = (service_host or "" ).lower ()
57
-
58
- # Block when hostnames match (port is irrelevant)
59
- return target_host == service_hostname
60
- except Exception :
61
- # If URL parsing fails, allow it (conservative approach)
62
- return False
37
+ return '' .join (random .choices (string .ascii_letters + string .digits , k = length ))
63
38
64
39
@app .post ("/shorten" )
65
40
def shorten_url (request : UrlRequest , http_request : Request ):
66
- # Check for self-referencing URLs to prevent infinite redirect loops
67
- # Prefer frontend-provided host; fallback to request host if needed
68
- current_host = request .service_host or http_request .url .hostname
69
- if is_self_referencing (request .url , current_host ):
70
- raise HTTPException (
71
- status_code = 400 ,
72
- detail = "Cannot shorten URLs that point to this service - this would create an infinite redirect loop. Please use an external URL instead."
73
- )
74
-
75
- if request .url in url_store .values ():
76
- raise HTTPException (status_code = 400 , detail = "URL was already shortened previously" )
77
-
78
- short_code = generate_short_code ()
79
- while short_code in url_store :
80
- short_code = generate_short_code ()
81
-
82
- url_store [short_code ] = request .url
83
-
84
- # Initialize click stats for the new URL
85
- click_stats [short_code ] = ClickStatsData (
86
- count = 0 ,
87
- original_url = request .url
88
- )
89
-
90
- return short_code
41
+ # TODO: implement this function
42
+ # 1. Generate short code for long url
43
+ # 2. Store the mapping of short code to long url
44
+ # 3. Optional: store click_stats using the class ClickStatsData for the short_code with initial values
45
+ short_code = ""
46
+ return {short_code }
91
47
92
48
@app .get ("/get-long-url/{short_code}" )
93
49
def get_long_url (short_code : str ):
94
- if short_code in url_store :
95
- # Track clicks
96
- if short_code not in click_stats :
97
- click_stats [short_code ] = ClickStatsData (
98
- count = 0 ,
99
- original_url = url_store [short_code ]
100
- )
101
-
102
- click_stats [short_code ].count += 1
103
- return url_store [short_code ]
104
-
105
- raise HTTPException (status_code = 404 , detail = "Short URL not found" )
106
-
50
+ # TODO: implement this function
51
+ # 1. Fetch the long URL from the url_store using the short_code
52
+ # 2. Return HTTP 404 (not found) if the short_code is not found
53
+ # 3. (Optional) Update the click statistics in click_stats for the short_code
54
+ long_url = ""
55
+ return {long_url }
107
56
108
57
@app .get ("/get-qr-code/{url}" )
109
58
def get_qr_code (url : str ):
110
- # URL decode the parameter to handle special characters
111
- decoded_url = url
112
-
113
- qr = qrcode .QRCode (
114
- version = 1 ,
115
- error_correction = qrcode .constants .ERROR_CORRECT_L ,
116
- box_size = 10 ,
117
- border = 0 ,
118
- )
119
- qr .add_data (decoded_url )
120
- qr .make (fit = True )
121
- img = qr .make_image (fill_color = "black" , back_color = "white" )
122
- buf = io .BytesIO ()
123
- img .save (buf , format = "PNG" )
124
- buf .seek (0 )
125
- encoded_string = base64 .b64encode (buf .read ()).decode ("utf-8" )
126
- return {"image_base64" : f"data:image/png;base64,{ encoded_string } " }
59
+ # TODO: implement this function
60
+ # 1. Generate a QR code for the given url parameter
61
+ # 2. Return the QR code image as a base64-encoded string
62
+ # Hint: You can use the qrcode library to generate QR codes.
63
+ # Take a look at the documentation here: https://pypi.org/project/qrcode/
64
+ encoded_string = ""
65
+ # return {"image_base64": f"data:image/png;base64,{encoded_string}"}
127
66
128
67
# Click Statistics Endpoints
129
68
@app .get ("/stats" , response_model = List [ClickStats ])
@@ -160,21 +99,20 @@ def get_stats_for_url(short_code: str):
160
99
"click_count" : data .count ,
161
100
}
162
101
163
- # Returns simple string message
164
102
@app .get ("/example" )
165
103
def example_endpoint (param : str ):
166
- if param == "error" :
167
- raise HTTPException (status_code = 400 , detail = "Invalid parameter value" )
168
- return {"message" : f"This is an example endpoint with parameter: { param } " }
104
+ if param == "error" :
105
+ raise HTTPException (status_code = 400 , detail = "Invalid parameter value" )
106
+ return {"message" : f"This is an example endpoint with parameter: { param } " }
169
107
170
108
# Returns image in base64 format
171
109
@app .get ("/example-image" )
172
110
def example_image_endpoint ():
173
- file_path = "image.jpeg"
174
- if os .path .exists (file_path ):
175
- with open (file_path , "rb" ) as image_file :
176
- encoded_string = base64 .b64encode (image_file .read ()).decode ('utf-8' )
177
- prefix = "data:image/jpeg;base64,"
178
- return {"image_base64" : prefix + encoded_string }
179
- else :
180
- raise HTTPException (status_code = 404 , detail = "Image not found" )
111
+ file_path = "image.jpeg"
112
+ if os .path .exists (file_path ):
113
+ with open (file_path , "rb" ) as image_file :
114
+ encoded_string = base64 .b64encode (image_file .read ()).decode ('utf-8' )
115
+ prefix = "data:image/jpeg;base64,"
116
+ return {"image_base64" : prefix + encoded_string }
117
+ else :
118
+ raise HTTPException (status_code = 404 , detail = "Image not found" )
0 commit comments