1+ <!DOCTYPE html>
2+ < html >
3+
4+ < head >
5+ < title > Export API Test</ title >
6+ < style >
7+ body {
8+ font-family : Arial, sans-serif;
9+ margin : 20px ;
10+ background : # f0f0f0 ;
11+ }
12+
13+ .container {
14+ max-width : 900px ;
15+ margin : 0 auto;
16+ background : white;
17+ padding : 20px ;
18+ border-radius : 8px ;
19+ box-shadow : 0 2px 4px rgba (0 , 0 , 0 , 0.1 );
20+ }
21+
22+ button {
23+ padding : 10px 20px ;
24+ margin : 5px ;
25+ background : # 4CAF50 ;
26+ color : white;
27+ border : none;
28+ border-radius : 4px ;
29+ cursor : pointer;
30+ font-size : 16px ;
31+ }
32+
33+ button : hover {
34+ background : # 45a049 ;
35+ }
36+
37+ button : disabled {
38+ background : # ccc ;
39+ cursor : not-allowed;
40+ }
41+
42+ # output {
43+ background : # f9f9f9 ;
44+ border : 1px solid # ddd ;
45+ padding : 15px ;
46+ margin-top : 10px ;
47+ white-space : pre-wrap;
48+ font-family : monospace;
49+ font-size : 12px ;
50+ max-height : 600px ;
51+ overflow-y : auto;
52+ }
53+
54+ .success {
55+ color : green;
56+ }
57+
58+ .error {
59+ color : red;
60+ }
61+
62+ .warning {
63+ color : orange;
64+ }
65+
66+ .info {
67+ color : blue;
68+ }
69+
70+ input {
71+ padding : 8px ;
72+ margin : 5px ;
73+ width : 300px ;
74+ font-size : 14px ;
75+ }
76+ </ style >
77+ </ head >
78+
79+ < body >
80+ < div class ="container ">
81+ < h1 > Export API Direct Test</ h1 >
82+ < p > This page tests the export API directly without React to isolate any issues.</ p >
83+
84+ < div >
85+ < h3 > Step 1: Login</ h3 >
86+ < input type ="text " id ="username " placeholder ="Username " value ="testuser_2 " />
87+ < input type ="password " id ="password " placeholder ="Password " value ="testpass " />
88+ < button onclick ="doLogin() "> Login</ button >
89+ </ div >
90+
91+ < div style ="margin-top: 20px; ">
92+ < h3 > Step 2: Export Canvas</ h3 >
93+ < input type ="text " id ="roomId " placeholder ="Room ID " value ="68e1e5215b4cd832202ae54f " />
94+ < button onclick ="doExport() " id ="exportBtn " disabled > Export</ button >
95+ < button onclick ="clearOutput() "> Clear Log</ button >
96+ </ div >
97+
98+ < div id ="output "> </ div >
99+ </ div >
100+
101+ < script >
102+ let token = null ;
103+ const API_BASE = 'http://localhost:10010' ;
104+
105+ function log ( message , type = 'info' ) {
106+ const output = document . getElementById ( 'output' ) ;
107+ const timestamp = new Date ( ) . toLocaleTimeString ( ) ;
108+ const className = type ;
109+ output . innerHTML += `<span class="${ className } ">[${ timestamp } ] ${ message } </span>\n` ;
110+ output . scrollTop = output . scrollHeight ;
111+ console . log ( `[${ type } ]` , message ) ;
112+ }
113+
114+ function clearOutput ( ) {
115+ document . getElementById ( 'output' ) . innerHTML = '' ;
116+ }
117+
118+ async function doLogin ( ) {
119+ try {
120+ const username = document . getElementById ( 'username' ) . value ;
121+ const password = document . getElementById ( 'password' ) . value ;
122+
123+ log ( '=== LOGIN ATTEMPT ===' , 'info' ) ;
124+ log ( `Username: ${ username } ` , 'info' ) ;
125+ log ( `API Base: ${ API_BASE } ` , 'info' ) ;
126+
127+ const response = await fetch ( `${ API_BASE } /auth/login` , {
128+ method : 'POST' ,
129+ headers : { 'Content-Type' : 'application/json' } ,
130+ body : JSON . stringify ( { username, password } )
131+ } ) ;
132+
133+ log ( `Response status: ${ response . status } ${ response . statusText } ` , response . ok ? 'success' : 'error' ) ;
134+
135+ const data = await response . json ( ) ;
136+ log ( `Response data: ${ JSON . stringify ( data , null , 2 ) } ` , 'info' ) ;
137+
138+ if ( response . ok && data . token ) {
139+ token = data . token ;
140+ log ( '✓ Login successful! Token received.' , 'success' ) ;
141+ log ( `Token (first 50 chars): ${ token . substring ( 0 , 50 ) } ...` , 'info' ) ;
142+ document . getElementById ( 'exportBtn' ) . disabled = false ;
143+ } else {
144+ log ( '✗ Login failed!' , 'error' ) ;
145+ log ( `Error: ${ data . message || 'Unknown error' } ` , 'error' ) ;
146+ }
147+ } catch ( error ) {
148+ log ( `✗ Exception during login: ${ error . message } ` , 'error' ) ;
149+ log ( `Stack: ${ error . stack } ` , 'error' ) ;
150+ }
151+ }
152+
153+ async function doExport ( ) {
154+ try {
155+ const roomId = document . getElementById ( 'roomId' ) . value ;
156+
157+ log ( '\n=== EXPORT ATTEMPT ===' , 'info' ) ;
158+ log ( `Room ID: ${ roomId } ` , 'info' ) ;
159+ log ( `Token present: ${ ! ! token } ` , 'info' ) ;
160+
161+ if ( ! token ) {
162+ log ( '✗ No token! Please login first.' , 'error' ) ;
163+ return ;
164+ }
165+
166+ const url = `${ API_BASE } /api/rooms/${ roomId } /export` ;
167+ log ( `Full URL: ${ url } ` , 'info' ) ;
168+
169+ log ( 'Sending GET request...' , 'info' ) ;
170+ const response = await fetch ( url , {
171+ method : 'GET' ,
172+ headers : {
173+ 'Authorization' : `Bearer ${ token } `
174+ }
175+ } ) ;
176+
177+ log ( `Response received!` , 'success' ) ;
178+ log ( `Status: ${ response . status } ${ response . statusText } ` , response . ok ? 'success' : 'error' ) ;
179+ log ( `Response OK: ${ response . ok } ` , 'info' ) ;
180+ log ( `Content-Type: ${ response . headers . get ( 'content-type' ) } ` , 'info' ) ;
181+
182+ const responseText = await response . text ( ) ;
183+ log ( `Response body length: ${ responseText . length } characters` , 'info' ) ;
184+ log ( `Response body (first 500 chars):\n${ responseText . substring ( 0 , 500 ) } ` , 'info' ) ;
185+
186+ let parsedData ;
187+ try {
188+ parsedData = JSON . parse ( responseText ) ;
189+ log ( '✓ JSON parsing successful' , 'success' ) ;
190+ } catch ( parseError ) {
191+ log ( '✗ JSON parsing failed!' , 'error' ) ;
192+ log ( `Parse error: ${ parseError . message } ` , 'error' ) ;
193+ return ;
194+ }
195+
196+ log ( `\nParsed data structure:` , 'info' ) ;
197+ log ( ` - Type: ${ typeof parsedData } ` , 'info' ) ;
198+ log ( ` - Keys: ${ Object . keys ( parsedData ) . join ( ', ' ) } ` , 'info' ) ;
199+ log ( ` - Has 'status': ${ ! ! parsedData . status } ` , 'info' ) ;
200+ log ( ` - Has 'data': ${ ! ! parsedData . data } ` , 'info' ) ;
201+
202+ if ( parsedData . data ) {
203+ const exportData = parsedData . data ;
204+ log ( `\nExport data structure:` , 'success' ) ;
205+ log ( ` - Keys: ${ Object . keys ( exportData ) . join ( ', ' ) } ` , 'success' ) ;
206+ log ( ` - Room ID: ${ exportData . roomId } ` , 'success' ) ;
207+ log ( ` - Room Name: ${ exportData . roomName } ` , 'success' ) ;
208+ log ( ` - Stroke Count: ${ exportData . strokeCount } ` , 'success' ) ;
209+ log ( ` - Has strokes array: ${ ! ! exportData . strokes } ` , 'success' ) ;
210+ log ( ` - Strokes array length: ${ exportData . strokes ? exportData . strokes . length : 'N/A' } ` , 'success' ) ;
211+
212+ if ( exportData . strokes && exportData . strokes . length > 0 ) {
213+ log ( `\nFirst stroke sample:` , 'info' ) ;
214+ log ( JSON . stringify ( exportData . strokes [ 0 ] , null , 2 ) . substring ( 0 , 300 ) , 'info' ) ;
215+ }
216+
217+ log ( '\n✓✓✓ EXPORT TEST PASSED ✓✓✓' , 'success' ) ;
218+ log ( 'The API is returning data correctly!' , 'success' ) ;
219+
220+ // Download the file
221+ const dataStr = JSON . stringify ( parsedData . data , null , 2 ) ;
222+ const dataBlob = new Blob ( [ dataStr ] , { type : 'application/json' } ) ;
223+ const url = URL . createObjectURL ( dataBlob ) ;
224+ const link = document . createElement ( 'a' ) ;
225+ link . href = url ;
226+ link . download = `export_test_${ Date . now ( ) } .json` ;
227+ document . body . appendChild ( link ) ;
228+ link . click ( ) ;
229+ document . body . removeChild ( link ) ;
230+ URL . revokeObjectURL ( url ) ;
231+
232+ log ( '✓ Downloaded export file!' , 'success' ) ;
233+ } else {
234+ log ( '✗ Response missing "data" key!' , 'error' ) ;
235+ log ( `Full response: ${ JSON . stringify ( parsedData , null , 2 ) } ` , 'warning' ) ;
236+ }
237+
238+ } catch ( error ) {
239+ log ( `\n✗ Exception during export: ${ error . message } ` , 'error' ) ;
240+ log ( `Stack: ${ error . stack } ` , 'error' ) ;
241+ }
242+ }
243+
244+ // Auto-log page load
245+ log ( 'Export API Test Page Loaded' , 'success' ) ;
246+ log ( `Testing against: ${ API_BASE } ` , 'info' ) ;
247+ log ( 'Click "Login" to authenticate, then "Export" to test the API.' , 'info' ) ;
248+ </ script >
249+ </ body >
250+
251+ </ html >
0 commit comments