SalexAI commited on
Commit
ae7a763
·
verified ·
1 Parent(s): 3f5f4d1

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +209 -26
app.py CHANGED
@@ -1,37 +1,220 @@
1
  from fastapi import FastAPI, Request
2
- from fastapi.responses import HTMLResponse, RedirectResponse
3
- import urllib.parse
 
4
  import os
5
 
6
  app = FastAPI()
7
- STORAGE_FILE = "data.txt"
8
 
9
- # Initialize file
10
- if not os.path.exists(STORAGE_FILE):
11
- with open(STORAGE_FILE, "w") as f:
12
- f.write("")
 
 
 
13
 
14
- def read_data():
15
- with open(STORAGE_FILE, "r") as f:
16
- return f.read()
 
17
 
18
- def write_data(data: str):
19
- with open(STORAGE_FILE, "w") as f:
20
- f.write(data)
21
-
22
- @app.get("/store")
23
  async def store(request: Request):
24
- lists = request.query_params.get("lists")
25
- if lists:
26
- decoded = urllib.parse.unquote(lists)
27
- write_data(decoded)
28
- return RedirectResponse(url="/") # Redirect back to main page
29
- return {"status": "error", "message": "Missing 'lists' query parameter."}
30
 
31
  @app.get("/", response_class=HTMLResponse)
32
  async def index():
33
- stored_data = urllib.parse.quote(read_data())
34
- with open("index.html", "r", encoding="utf-8") as f:
35
- html = f.read()
36
- # Inject the stored data into the ?lists= param
37
- return HTMLResponse(content=html.replace("?lists=", f"?lists={stored_data}"), status_code=200)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  from fastapi import FastAPI, Request
2
+ from fastapi.responses import HTMLResponse
3
+ from fastapi.middleware.cors import CORSMiddleware
4
+ import json
5
  import os
6
 
7
  app = FastAPI()
8
+ DATA_FILE = "data.json"
9
 
10
+ # Allow CORS for frontend fetch if needed
11
+ app.add_middleware(
12
+ CORSMiddleware,
13
+ allow_origins=["*"],
14
+ allow_methods=["*"],
15
+ allow_headers=["*"],
16
+ )
17
 
18
+ # Initialize data file
19
+ if not os.path.exists(DATA_FILE):
20
+ with open(DATA_FILE, "w") as f:
21
+ json.dump([], f)
22
 
23
+ @app.post("/store")
 
 
 
 
24
  async def store(request: Request):
25
+ data = await request.json()
26
+ with open(DATA_FILE, "w") as f:
27
+ json.dump(data, f)
28
+ return {"status": "success"}
 
 
29
 
30
  @app.get("/", response_class=HTMLResponse)
31
  async def index():
32
+ with open(DATA_FILE, "r") as f:
33
+ stored_data = json.load(f)
34
+ # Escape the JSON and inject it into the script
35
+ return HTMLResponse(content=f"""
36
+ <!DOCTYPE html>
37
+ <html lang="en">
38
+ <head>
39
+ <meta charset="UTF-8" />
40
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
41
+ <title>UniShare</title>
42
+ <style>
43
+ body {{
44
+ font-family: Arial, sans-serif;
45
+ margin: 0;
46
+ padding: 0;
47
+ background: #f0f2f5;
48
+ }}
49
+ header {{
50
+ background: #3b82f6;
51
+ color: white;
52
+ padding: 1em;
53
+ text-align: center;
54
+ font-size: 1.8em;
55
+ }}
56
+ #overview {{
57
+ display: grid;
58
+ grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
59
+ gap: 1em;
60
+ padding: 1em;
61
+ }}
62
+ .list-tile {{
63
+ background: white;
64
+ padding: 1em;
65
+ border-radius: 10px;
66
+ box-shadow: 0 2px 5px rgba(0,0,0,0.1);
67
+ cursor: pointer;
68
+ transition: transform 0.2s;
69
+ }}
70
+ .list-tile:hover {{
71
+ transform: scale(1.02);
72
+ }}
73
+ #list-view {{
74
+ display: none;
75
+ padding: 1em;
76
+ }}
77
+ .back-button {{
78
+ background: #3b82f6;
79
+ color: white;
80
+ padding: 0.5em 1em;
81
+ border: none;
82
+ border-radius: 5px;
83
+ cursor: pointer;
84
+ margin-bottom: 1em;
85
+ }}
86
+ .card {{
87
+ background: white;
88
+ padding: 1em;
89
+ border-radius: 10px;
90
+ box-shadow: 0 2px 5px rgba(0,0,0,0.1);
91
+ margin-bottom: 1em;
92
+ }}
93
+ .submenu {{
94
+ margin-top: 1em;
95
+ }}
96
+ .submenu h4 {{
97
+ margin: 0.5em 0;
98
+ }}
99
+ .grid {{
100
+ display: grid;
101
+ grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
102
+ gap: 1em;
103
+ }}
104
+ .item {{
105
+ background: #f9f9f9;
106
+ padding: 1em;
107
+ border-radius: 10px;
108
+ box-shadow: 0 1px 3px rgba(0,0,0,0.05);
109
+ }}
110
+ .item img {{
111
+ max-width: 100%;
112
+ max-height: 150px;
113
+ object-fit: cover;
114
+ border-radius: 5px;
115
+ margin-bottom: 0.5em;
116
+ }}
117
+ .item a {{
118
+ display: inline-block;
119
+ margin-top: 0.5em;
120
+ text-decoration: none;
121
+ color: #3b82f6;
122
+ }}
123
+ #toast {{
124
+ position: fixed;
125
+ bottom: 20px;
126
+ right: 20px;
127
+ background: #333;
128
+ color: white;
129
+ padding: 1em;
130
+ border-radius: 5px;
131
+ display: none;
132
+ z-index: 1000;
133
+ }}
134
+ </style>
135
+ </head>
136
+ <body>
137
+ <header>UniShare</header>
138
+ <div id="overview"></div>
139
+ <div id="list-view">
140
+ <button class="back-button" onclick="backToOverview()">← Back to Overview</button>
141
+ <div id="content"></div>
142
+ </div>
143
+ <div id="toast"></div>
144
+
145
+ <script>
146
+ const overviewDiv = document.getElementById('overview');
147
+ const contentDiv = document.getElementById('content');
148
+ const listViewDiv = document.getElementById('list-view');
149
+ const toastDiv = document.getElementById('toast');
150
+
151
+ const rawData = {json.dumps(stored_data)};
152
+ const lists = {{}};
153
+
154
+ function showToast(message) {{
155
+ toastDiv.textContent = message;
156
+ toastDiv.style.display = 'block';
157
+ setTimeout(() => {{
158
+ toastDiv.style.display = 'none';
159
+ }}, 3000);
160
+ }}
161
+
162
+ function backToOverview() {{
163
+ listViewDiv.style.display = 'none';
164
+ overviewDiv.style.display = 'grid';
165
+ }}
166
+
167
+ function showList(name) {{
168
+ const sections = lists[name];
169
+ contentDiv.innerHTML = '';
170
+
171
+ sections.forEach(section => {{
172
+ const card = document.createElement('div');
173
+ card.className = 'card';
174
+ const title = document.createElement('h3');
175
+ title.textContent = section.sectionTitle;
176
+ card.appendChild(title);
177
+
178
+ const grid = document.createElement('div');
179
+ grid.className = 'grid';
180
+
181
+ section.items.forEach(item => {{
182
+ const div = document.createElement('div');
183
+ div.className = 'item';
184
+ let content = `<strong>${{item.title}}</strong><br>`;
185
+ if (item.link.match(/\\.(jpeg|jpg|gif|png)$/)) {{
186
+ content += `<img src="${{item.link}}" alt="${{item.title}}" />`;
187
+ }}
188
+ content += `<a href="${{item.link}}" download>Download</a>`;
189
+ div.innerHTML = content;
190
+ grid.appendChild(div);
191
+ }});
192
+
193
+ card.appendChild(grid);
194
+ contentDiv.appendChild(card);
195
+ }});
196
+
197
+ overviewDiv.style.display = 'none';
198
+ listViewDiv.style.display = 'block';
199
+ }}
200
+
201
+ rawData.forEach((list, index) => {{
202
+ if (Array.isArray(list)) {{
203
+ const listName = `List ${{index + 1}}`;
204
+ lists[listName] = list;
205
+ const tile = document.createElement('div');
206
+ tile.className = 'list-tile';
207
+ tile.innerHTML = `<strong>${{listName}}</strong><br>${{list.length}} sections`;
208
+ tile.onclick = () => showList(listName);
209
+ overviewDiv.appendChild(tile);
210
+ showToast(`Loaded ${{listName}}`);
211
+ }}
212
+ }});
213
+
214
+ if (Object.keys(lists).length === 0) {{
215
+ overviewDiv.innerHTML = '<p style="padding:1em">No valid list data available.</p>';
216
+ }}
217
+ </script>
218
+ </body>
219
+ </html>
220
+ """, status_code=200)