CatPtain commited on
Commit
bcc9a86
·
verified ·
1 Parent(s): 69c1665

Upload 10 files

Browse files
Files changed (6) hide show
  1. .env +24 -0
  2. editor.html +3 -3
  3. github-test.html +231 -0
  4. index.html +101 -145
  5. save.php +37 -9
  6. storage.php +50 -1
.env ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Storage Configuration
2
+ STORAGE_TYPE=github
3
+
4
+ # GitHub Configuration
5
+ GITHUB_TOKEN=ghp_your_token_here
6
+ GITHUB_OWNER=CaPaCaptain
7
+ GITHUB_REPO=VvvebJs_huggingface_db_01
8
+ GITHUB_BRANCH=main
9
+ GITHUB_PATH=pages/
10
+
11
+ # User Configuration
12
+ USER_1_NAME=PS01
13
+ USER_1_PASSWORD=password123
14
+ USER_2_NAME=PS02
15
+ USER_2_PASSWORD=password456
16
+ USER_3_NAME=admin
17
+ USER_3_PASSWORD=admin123
18
+
19
+ # Optional: EdgeOne KV Configuration (if using KV storage)
20
+ # EDGEONE_KV_API_KEY=your_api_key_here
21
+ # EDGEONE_KV_SECRET_KEY=your_secret_key_here
22
+ # EDGEONE_KV_ZONE_ID=your_zone_id_here
23
+ # EDGEONE_KV_NAMESPACE=vvvebjs
24
+ # EDGEONE_KV_ENDPOINT=https://edgeone.tencentcloudapi.com
editor.html CHANGED
@@ -211,16 +211,16 @@
211
 
212
 
213
  <div class="btn-group me-2 float-end" role="group">
214
- <button class="btn btn-primary btn-sm btn-icon save-btn" title="Save to GitHub (Ctrl + S)" id="save-btn" data-vvveb-action="saveAjax" data-vvveb-url="save.php" data-v-vvveb-shortcut="ctrl+e">
215
 
216
  <span class="loading d-none">
217
  <i class="icon-save-outline"></i>
218
  <span class="spinner-border spinner-border-sm align-middle" role="status" aria-hidden="true">
219
  </span>
220
- <span>Saving to GitHub</span> ... </span>
221
 
222
  <span class="button-text">
223
- <i class="icon-save-outline"></i> <span>Save to GitHub</span>
224
  </span>
225
 
226
  </button>
 
211
 
212
 
213
  <div class="btn-group me-2 float-end" role="group">
214
+ <button class="btn btn-primary btn-sm btn-icon save-btn" title="Save (Ctrl + S)" id="save-btn" data-vvveb-action="saveAjax" data-vvveb-url="save.php" data-v-vvveb-shortcut="ctrl+e">
215
 
216
  <span class="loading d-none">
217
  <i class="icon-save-outline"></i>
218
  <span class="spinner-border spinner-border-sm align-middle" role="status" aria-hidden="true">
219
  </span>
220
+ <span>Saving</span> ... </span>
221
 
222
  <span class="button-text">
223
+ <i class="icon-save-outline"></i> <span>SAVE</span>
224
  </span>
225
 
226
  </button>
github-test.html ADDED
@@ -0,0 +1,231 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>GitHub Configuration Test</title>
7
+ <style>
8
+ body { font-family: Arial, sans-serif; max-width: 800px; margin: 20px auto; padding: 20px; }
9
+ .config-section { background: #f8f9fa; padding: 20px; margin: 20px 0; border-radius: 8px; }
10
+ .success { color: #28a745; }
11
+ .error { color: #dc3545; }
12
+ .warning { color: #ffc107; }
13
+ .info { color: #17a2b8; }
14
+ .token-input { width: 100%; padding: 8px; margin: 5px 0; font-family: monospace; }
15
+ .btn { padding: 10px 20px; margin: 5px; border: none; border-radius: 4px; cursor: pointer; }
16
+ .btn-primary { background: #007bff; color: white; }
17
+ .btn-success { background: #28a745; color: white; }
18
+ pre { background: #f1f1f1; padding: 10px; border-radius: 4px; overflow-x: auto; }
19
+ </style>
20
+ </head>
21
+ <body>
22
+ <h1>🔧 GitHub Configuration & Test</h1>
23
+
24
+ <div class="config-section">
25
+ <h2>1. GitHub Token Configuration</h2>
26
+ <p>Enter your GitHub Personal Access Token below:</p>
27
+ <input type="password" id="github-token" class="token-input" placeholder="ghp_your_token_here">
28
+ <br>
29
+ <button class="btn btn-primary" onclick="testGitHubConnection()">Test GitHub Connection</button>
30
+ <button class="btn btn-success" onclick="saveToken()">Save Token to .env</button>
31
+
32
+ <div id="token-result"></div>
33
+
34
+ <h3>How to get GitHub Token:</h3>
35
+ <ol>
36
+ <li>Go to <a href="https://github.com/settings/tokens" target="_blank">GitHub Settings → Developer settings → Personal access tokens</a></li>
37
+ <li>Click "Generate new token" → "Generate new token (classic)"</li>
38
+ <li>Give it a name like "VvvebJs"</li>
39
+ <li>Select scopes: <strong>repo</strong> (full repository access)</li>
40
+ <li>Click "Generate token"</li>
41
+ <li>Copy the token and paste it above</li>
42
+ </ol>
43
+ </div>
44
+
45
+ <div class="config-section">
46
+ <h2>2. Repository Configuration</h2>
47
+ <p><strong>Repository:</strong> CaPaCaptain/VvvebJs_huggingface_db_01</p>
48
+ <p><strong>Branch:</strong> main</p>
49
+ <p><strong>Path:</strong> pages/</p>
50
+ <button class="btn btn-primary" onclick="testRepoAccess()">Test Repository Access</button>
51
+ <div id="repo-result"></div>
52
+ </div>
53
+
54
+ <div class="config-section">
55
+ <h2>3. File Operations Test</h2>
56
+ <button class="btn btn-primary" onclick="testFileList()">Test File List</button>
57
+ <button class="btn btn-primary" onclick="testFileSave()">Test File Save</button>
58
+ <div id="file-result"></div>
59
+ </div>
60
+
61
+ <div class="config-section">
62
+ <h2>4. Debug Information</h2>
63
+ <button class="btn btn-primary" onclick="getDebugInfo()">Get Debug Info</button>
64
+ <div id="debug-result"></div>
65
+ </div>
66
+
67
+ <script>
68
+ async function testGitHubConnection() {
69
+ const token = document.getElementById('github-token').value;
70
+ const resultDiv = document.getElementById('token-result');
71
+
72
+ if (!token) {
73
+ resultDiv.innerHTML = '<p class="error">❌ Please enter a GitHub token</p>';
74
+ return;
75
+ }
76
+
77
+ resultDiv.innerHTML = '<p class="info">🔄 Testing GitHub connection...</p>';
78
+
79
+ try {
80
+ const response = await fetch('https://api.github.com/user', {
81
+ headers: {
82
+ 'Authorization': `token ${token}`,
83
+ 'User-Agent': 'VvvebJs-Test'
84
+ }
85
+ });
86
+
87
+ if (response.ok) {
88
+ const user = await response.json();
89
+ resultDiv.innerHTML = `
90
+ <p class="success">✅ GitHub connection successful!</p>
91
+ <p>User: ${user.login} (${user.name || 'No name'})</p>
92
+ <p>API Rate Limit: ${response.headers.get('x-ratelimit-remaining')}/${response.headers.get('x-ratelimit-limit')}</p>
93
+ `;
94
+ } else {
95
+ const error = await response.json();
96
+ resultDiv.innerHTML = `
97
+ <p class="error">❌ GitHub connection failed!</p>
98
+ <p>Status: ${response.status}</p>
99
+ <p>Error: ${error.message || 'Unknown error'}</p>
100
+ `;
101
+ }
102
+ } catch (error) {
103
+ resultDiv.innerHTML = `<p class="error">❌ Network error: ${error.message}</p>`;
104
+ }
105
+ }
106
+
107
+ async function testRepoAccess() {
108
+ const token = document.getElementById('github-token').value;
109
+ const resultDiv = document.getElementById('repo-result');
110
+
111
+ if (!token) {
112
+ resultDiv.innerHTML = '<p class="error">❌ Please enter a GitHub token first</p>';
113
+ return;
114
+ }
115
+
116
+ resultDiv.innerHTML = '<p class="info">🔄 Testing repository access...</p>';
117
+
118
+ try {
119
+ const response = await fetch('https://api.github.com/repos/CaPaCaptain/VvvebJs_huggingface_db_01', {
120
+ headers: {
121
+ 'Authorization': `token ${token}`,
122
+ 'User-Agent': 'VvvebJs-Test'
123
+ }
124
+ });
125
+
126
+ if (response.ok) {
127
+ const repo = await response.json();
128
+ resultDiv.innerHTML = `
129
+ <p class="success">✅ Repository access successful!</p>
130
+ <p>Repository: ${repo.full_name}</p>
131
+ <p>Default Branch: ${repo.default_branch}</p>
132
+ <p>Private: ${repo.private ? 'Yes' : 'No'}</p>
133
+ <p>Permissions: ${JSON.stringify(repo.permissions || {})}</p>
134
+ `;
135
+ } else {
136
+ const error = await response.json();
137
+ resultDiv.innerHTML = `
138
+ <p class="error">❌ Repository access failed!</p>
139
+ <p>Status: ${response.status}</p>
140
+ <p>Error: ${error.message || 'Unknown error'}</p>
141
+ `;
142
+ }
143
+ } catch (error) {
144
+ resultDiv.innerHTML = `<p class="error">❌ Network error: ${error.message}</p>`;
145
+ }
146
+ }
147
+
148
+ async function testFileList() {
149
+ const resultDiv = document.getElementById('file-result');
150
+ resultDiv.innerHTML = '<p class="info">🔄 Testing file list...</p>';
151
+
152
+ try {
153
+ const response = await fetch('save.php?action=listFiles');
154
+ const data = await response.json();
155
+
156
+ resultDiv.innerHTML = `
157
+ <h3>File List Result:</h3>
158
+ <pre>${JSON.stringify(data, null, 2)}</pre>
159
+ `;
160
+ } catch (error) {
161
+ resultDiv.innerHTML = `<p class="error">❌ Error: ${error.message}</p>`;
162
+ }
163
+ }
164
+
165
+ async function testFileSave() {
166
+ const resultDiv = document.getElementById('file-result');
167
+ resultDiv.innerHTML = '<p class="info">🔄 Testing file save...</p>';
168
+
169
+ const testHtml = `<!DOCTYPE html>
170
+ <html>
171
+ <head><title>Test Page</title></head>
172
+ <body><h1>Test Page Created at ${new Date().toISOString()}</h1></body>
173
+ </html>`;
174
+
175
+ try {
176
+ const formData = new FormData();
177
+ formData.append('html', testHtml);
178
+ formData.append('file', 'test-page.html');
179
+
180
+ const response = await fetch('save.php', {
181
+ method: 'POST',
182
+ body: formData
183
+ });
184
+
185
+ const result = await response.text();
186
+ resultDiv.innerHTML = `
187
+ <h3>File Save Result:</h3>
188
+ <pre>${result}</pre>
189
+ `;
190
+ } catch (error) {
191
+ resultDiv.innerHTML = `<p class="error">❌ Error: ${error.message}</p>`;
192
+ }
193
+ }
194
+
195
+ async function getDebugInfo() {
196
+ const resultDiv = document.getElementById('debug-result');
197
+ resultDiv.innerHTML = '<p class="info">🔄 Getting debug info...</p>';
198
+
199
+ try {
200
+ const response = await fetch('save.php?action=checkAuth');
201
+ const data = await response.json();
202
+
203
+ resultDiv.innerHTML = `
204
+ <h3>Current Status:</h3>
205
+ <pre>${JSON.stringify(data, null, 2)}</pre>
206
+ `;
207
+ } catch (error) {
208
+ resultDiv.innerHTML = `<p class="error">❌ Error: ${error.message}</p>`;
209
+ }
210
+ }
211
+
212
+ async function saveToken() {
213
+ const token = document.getElementById('github-token').value;
214
+ const resultDiv = document.getElementById('token-result');
215
+
216
+ if (!token) {
217
+ resultDiv.innerHTML = '<p class="error">❌ Please enter a GitHub token</p>';
218
+ return;
219
+ }
220
+
221
+ // This would require a separate PHP endpoint to update the .env file
222
+ resultDiv.innerHTML = `
223
+ <p class="warning">⚠️ Manual Configuration Required</p>
224
+ <p>Please manually update your .env file with:</p>
225
+ <pre>GITHUB_TOKEN=${token}</pre>
226
+ <p>Or use the configuration interface in config.php</p>
227
+ `;
228
+ }
229
+ </script>
230
+ </body>
231
+ </html>
index.html CHANGED
@@ -3,8 +3,7 @@
3
  <head>
4
  <meta charset="UTF-8">
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <title>VvvebJs - Visual Website Builder</title>
7
- <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
8
  <style>
9
  body {
10
  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
@@ -12,212 +11,169 @@
12
  display: flex;
13
  align-items: center;
14
  justify-content: center;
15
- font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
 
16
  }
17
  .login-container {
18
- background: rgba(255, 255, 255, 0.95);
19
- border-radius: 20px;
20
- box-shadow: 0 20px 40px rgba(0,0,0,0.1);
21
  padding: 40px;
22
- min-width: 400px;
23
- backdrop-filter: blur(10px);
24
  }
25
- .login-header {
26
  text-align: center;
27
  margin-bottom: 30px;
 
 
 
28
  }
29
- .login-header h1 {
 
 
30
  color: #333;
31
- font-weight: 600;
32
  margin-bottom: 10px;
33
  }
34
- .login-header p {
 
 
 
35
  color: #666;
36
- margin: 0;
37
  }
38
- .form-control {
39
- border-radius: 10px;
40
- padding: 12px 16px;
41
- border: 2px solid #e1e5e9;
42
  margin-bottom: 20px;
43
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
44
  .form-control:focus {
 
45
  border-color: #667eea;
46
- box-shadow: 0 0 0 0.2rem rgba(102, 126, 234, 0.25);
47
  }
48
  .btn-login {
49
- background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
50
- border: none;
51
- border-radius: 10px;
52
  padding: 12px;
53
- font-weight: 600;
54
  color: white;
55
- width: 100%;
56
- margin-top: 10px;
 
 
 
 
57
  }
58
  .btn-login:hover {
59
- transform: translateY(-2px);
60
- box-shadow: 0 10px 25px rgba(102, 126, 234, 0.3);
61
- color: white;
62
- }
63
- .alert {
64
- border-radius: 10px;
65
- margin-bottom: 20px;
66
- }
67
- .features {
68
- margin-top: 30px;
69
- padding-top: 20px;
70
- border-top: 1px solid #e1e5e9;
71
- }
72
- .features h6 {
73
- color: #333;
74
- margin-bottom: 15px;
75
- }
76
- .features ul {
77
- color: #666;
78
- font-size: 14px;
79
- }
80
- .features ul li {
81
- margin-bottom: 8px;
82
  }
83
  </style>
84
  </head>
85
  <body>
86
  <div class="login-container">
87
- <div class="login-header">
88
- <h1>🎨 VvvebJs Editor</h1>
89
- <p>请登录以继续使用可视化网站编辑器</p>
90
  </div>
91
 
92
- <div id="alert-container"></div>
93
-
94
  <form id="loginForm">
95
  <div class="form-group">
96
- <label for="username" class="form-label">用户名</label>
97
- <input type="text" class="form-control" id="username" name="username" placeholder="请输入用户名" required>
98
  </div>
99
 
100
  <div class="form-group">
101
- <label for="password" class="form-label">密码</label>
102
- <input type="password" class="form-control" id="password" name="password" placeholder="请输入密码" required>
103
  </div>
104
 
105
- <button type="submit" class="btn btn-login">
106
- <span id="loginText">登录</span>
107
- <span id="loginSpinner" class="spinner-border spinner-border-sm d-none" role="status"></span>
108
- </button>
109
  </form>
110
 
111
- <div class="features">
112
- <h6>🚀 主要功能</h6>
113
- <ul>
114
- <li>🎨 可视化拖拽编辑器</li>
115
- <li>📱 Bootstrap 5 响应式组件</li>
116
- <li>💾 GitHub 云端存储,数据按用户隔离</li>
117
- <li>🔄 实时保存,多实例同步</li>
118
- <li>🔒 用户权限隔离,只能访问自己的文件</li>
119
- </ul>
120
- </div>
121
  </div>
122
 
123
  <script>
124
- // Check if already logged in
125
- window.onload = function() {
126
- fetch('user-manager.php', {
127
- method: 'POST',
128
- headers: {
129
- 'Content-Type': 'application/x-www-form-urlencoded',
130
- },
131
- body: 'action=check_login'
132
- })
133
- .then(response => response.json())
134
- .then(data => {
135
- if (data.logged_in) {
136
- // Already logged in, redirect to editor
137
- window.location.href = 'editor.html';
138
- }
139
- })
140
- .catch(error => {
141
- console.log('Auth check failed:', error);
142
- });
143
- };
144
-
145
- function showAlert(message, type = 'danger') {
146
- const alertContainer = document.getElementById('alert-container');
147
- alertContainer.innerHTML = `
148
- <div class="alert alert-${type} alert-dismissible fade show" role="alert">
149
- ${message}
150
- <button type="button" class="btn-close" data-bs-dismiss="alert"></button>
151
- </div>
152
- `;
153
- }
154
-
155
- function setLoading(loading) {
156
- const loginText = document.getElementById('loginText');
157
- const loginSpinner = document.getElementById('loginSpinner');
158
- const submitBtn = document.querySelector('.btn-login');
159
-
160
- if (loading) {
161
- loginText.classList.add('d-none');
162
- loginSpinner.classList.remove('d-none');
163
- submitBtn.disabled = true;
164
- } else {
165
- loginText.classList.remove('d-none');
166
- loginSpinner.classList.add('d-none');
167
- submitBtn.disabled = false;
168
- }
169
- }
170
-
171
  document.getElementById('loginForm').addEventListener('submit', async function(e) {
172
  e.preventDefault();
173
 
174
- const username = document.getElementById('username').value;
175
- const password = document.getElementById('password').value;
176
 
177
- if (!username || !password) {
178
- showAlert('请填写用户名和密码');
179
- return;
180
- }
181
-
182
- setLoading(true);
183
 
184
  try {
185
  const response = await fetch('user-manager.php', {
186
  method: 'POST',
187
- headers: {
188
- 'Content-Type': 'application/x-www-form-urlencoded',
189
- },
190
- body: `action=login&username=${encodeURIComponent(username)}&password=${encodeURIComponent(password)}`
191
  });
192
 
193
- const result = await response.json();
194
 
195
- if (result.success) {
196
- showAlert('登录成功正在跳转...', 'success');
 
 
 
197
  setTimeout(() => {
198
  window.location.href = 'editor.html';
199
  }, 1000);
200
  } else {
201
- showAlert(result.message || '登录失败');
202
- setLoading(false);
 
203
  }
204
  } catch (error) {
205
- showAlert('网络错误,请重试');
206
- setLoading(false);
 
207
  }
208
  });
209
 
210
- // Auto focus on username field
211
- document.getElementById('username').focus();
212
-
213
- // Allow Enter key to submit
214
- document.addEventListener('keypress', function(e) {
215
- if (e.key === 'Enter') {
216
- document.getElementById('loginForm').dispatchEvent(new Event('submit'));
 
 
217
  }
 
 
 
218
  });
219
  </script>
220
-
221
- <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
222
  </body>
223
  </html>
 
3
  <head>
4
  <meta charset="UTF-8">
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>VvvebJs Editor</title>
 
7
  <style>
8
  body {
9
  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
 
11
  display: flex;
12
  align-items: center;
13
  justify-content: center;
14
+ margin: 0;
15
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
16
  }
17
  .login-container {
18
+ background: white;
19
+ border-radius: 15px;
20
+ box-shadow: 0 15px 35px rgba(0,0,0,0.1);
21
  padding: 40px;
22
+ width: 400px;
23
+ max-width: 90vw;
24
  }
25
+ .header {
26
  text-align: center;
27
  margin-bottom: 30px;
28
+ padding: 20px;
29
+ border: 2px solid #dc3545;
30
+ border-radius: 8px;
31
  }
32
+ .logo {
33
+ font-size: 24px;
34
+ font-weight: bold;
35
  color: #333;
 
36
  margin-bottom: 10px;
37
  }
38
+ .logo::before {
39
+ content: "🎨 ";
40
+ }
41
+ .subtitle {
42
  color: #666;
43
+ font-size: 14px;
44
  }
45
+ .form-group {
 
 
 
46
  margin-bottom: 20px;
47
  }
48
+ .form-group label {
49
+ display: block;
50
+ margin-bottom: 8px;
51
+ color: #333;
52
+ font-weight: 500;
53
+ }
54
+ .form-control {
55
+ width: 100%;
56
+ padding: 12px 15px;
57
+ border: 1px solid #ddd;
58
+ border-radius: 6px;
59
+ font-size: 14px;
60
+ box-sizing: border-box;
61
+ }
62
  .form-control:focus {
63
+ outline: none;
64
  border-color: #667eea;
65
+ box-shadow: 0 0 0 2px rgba(102, 126, 234, 0.2);
66
  }
67
  .btn-login {
68
+ width: 100%;
 
 
69
  padding: 12px;
70
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
71
  color: white;
72
+ border: none;
73
+ border-radius: 6px;
74
+ font-size: 16px;
75
+ font-weight: 500;
76
+ cursor: pointer;
77
+ transition: all 0.3s;
78
  }
79
  .btn-login:hover {
80
+ background: linear-gradient(135deg, #5a6fd8 0%, #6a4190 100%);
81
+ transform: translateY(-1px);
82
+ box-shadow: 0 4px 12px rgba(102, 126, 234, 0.3);
83
+ }
84
+ .message {
85
+ margin-top: 15px;
86
+ padding: 10px;
87
+ border-radius: 4px;
88
+ display: none;
89
+ }
90
+ .message.error {
91
+ background: #f8d7da;
92
+ color: #721c24;
93
+ border: 1px solid #f5c6cb;
94
+ }
95
+ .message.success {
96
+ background: #d4edda;
97
+ color: #155724;
98
+ border: 1px solid #c3e6cb;
 
 
 
 
99
  }
100
  </style>
101
  </head>
102
  <body>
103
  <div class="login-container">
104
+ <div class="header">
105
+ <div class="logo">VvvebJs Editor</div>
106
+ <div class="subtitle">请登录以继续使用可视化网站编辑器</div>
107
  </div>
108
 
 
 
109
  <form id="loginForm">
110
  <div class="form-group">
111
+ <label for="username">用户名</label>
112
+ <input type="text" id="username" name="username" class="form-control" placeholder="请输入用户名" required>
113
  </div>
114
 
115
  <div class="form-group">
116
+ <label for="password">密码</label>
117
+ <input type="password" id="password" name="password" class="form-control" placeholder="请输入密码" required>
118
  </div>
119
 
120
+ <button type="submit" class="btn-login">登录</button>
 
 
 
121
  </form>
122
 
123
+ <div id="message" class="message"></div>
 
 
 
 
 
 
 
 
 
124
  </div>
125
 
126
  <script>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
127
  document.getElementById('loginForm').addEventListener('submit', async function(e) {
128
  e.preventDefault();
129
 
130
+ const formData = new FormData(this);
131
+ formData.append('action', 'login');
132
 
133
+ const messageDiv = document.getElementById('message');
 
 
 
 
 
134
 
135
  try {
136
  const response = await fetch('user-manager.php', {
137
  method: 'POST',
138
+ body: formData
 
 
 
139
  });
140
 
141
+ const data = await response.json();
142
 
143
+ if (data.success) {
144
+ messageDiv.textContent = '登录成功正在跳转...';
145
+ messageDiv.className = 'message success';
146
+ messageDiv.style.display = 'block';
147
+
148
  setTimeout(() => {
149
  window.location.href = 'editor.html';
150
  }, 1000);
151
  } else {
152
+ messageDiv.textContent = data.message || '登录失败';
153
+ messageDiv.className = 'message error';
154
+ messageDiv.style.display = 'block';
155
  }
156
  } catch (error) {
157
+ messageDiv.textContent = '网络错误,请重试';
158
+ messageDiv.className = 'message error';
159
+ messageDiv.style.display = 'block';
160
  }
161
  });
162
 
163
+ // 检查是否已登录
164
+ fetch('user-manager.php', {
165
+ method: 'POST',
166
+ body: new URLSearchParams({action: 'check_login'})
167
+ })
168
+ .then(response => response.json())
169
+ .then(data => {
170
+ if (data.logged_in) {
171
+ window.location.href = 'editor.html';
172
  }
173
+ })
174
+ .catch(error => {
175
+ console.log('登录状态检查失败:', error);
176
  });
177
  </script>
 
 
178
  </body>
179
  </html>
save.php CHANGED
@@ -138,15 +138,43 @@ if ($action) {
138
  //file manager actions, delete and rename
139
  switch ($action) {
140
  case 'listFiles':
141
- // List files for current user
142
- $files = $storageManager->listFiles();
143
- header('Content-Type: application/json');
144
- echo json_encode([
145
- 'success' => true,
146
- 'files' => $files,
147
- 'user' => $storageManager->getCurrentUser(),
148
- 'userPath' => $storageManager->getUserPath()
149
- ]);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
150
  exit;
151
 
152
  case 'loadFile':
 
138
  //file manager actions, delete and rename
139
  switch ($action) {
140
  case 'listFiles':
141
+ // List files for current user with enhanced error handling
142
+ try {
143
+ $files = $storageManager->listFiles();
144
+
145
+ // Enhanced debugging
146
+ $github = StorageConfig::getGitHubConfig();
147
+ $debug = [
148
+ 'hasToken' => !empty($github['token']),
149
+ 'owner' => $github['owner'],
150
+ 'repo' => $github['repo'],
151
+ 'branch' => $github['branch'],
152
+ 'path' => $github['path'],
153
+ 'user' => $storageManager->getCurrentUser(),
154
+ 'userPath' => $storageManager->getUserPath()
155
+ ];
156
+
157
+ error_log("GitHub List Files Debug: " . json_encode($debug));
158
+ error_log("Files found: " . count($files));
159
+
160
+ header('Content-Type: application/json');
161
+ echo json_encode([
162
+ 'success' => true,
163
+ 'files' => $files,
164
+ 'user' => $storageManager->getCurrentUser(),
165
+ 'userPath' => $storageManager->getUserPath(),
166
+ 'debug' => $debug
167
+ ]);
168
+ } catch (Exception $e) {
169
+ error_log("GitHub List Files Error: " . $e->getMessage());
170
+ header('Content-Type: application/json');
171
+ echo json_encode([
172
+ 'success' => false,
173
+ 'message' => 'Error loading files: ' . $e->getMessage(),
174
+ 'user' => $storageManager->getCurrentUser(),
175
+ 'files' => []
176
+ ]);
177
+ }
178
  exit;
179
 
180
  case 'loadFile':
storage.php CHANGED
@@ -1,7 +1,54 @@
1
  <?php
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2
  // Configuration management class
3
  class StorageConfig {
4
  public static function getUsers() {
 
 
 
 
 
 
 
5
  $users = [];
6
  $i = 1;
7
  while (true) {
@@ -15,7 +62,9 @@ class StorageConfig {
15
  $users[$username] = $password;
16
  $i++;
17
  }
18
- return $users;
 
 
19
  }
20
 
21
  public static function getStorageType() {
 
1
  <?php
2
+ // Load environment variables from .env file
3
+ function loadEnv($filePath) {
4
+ if (!file_exists($filePath)) {
5
+ return false;
6
+ }
7
+
8
+ $lines = file($filePath, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
9
+ foreach ($lines as $line) {
10
+ if (strpos(trim($line), '#') === 0) {
11
+ continue; // Skip comments
12
+ }
13
+
14
+ list($name, $value) = explode('=', $line, 2);
15
+ $name = trim($name);
16
+ $value = trim($value);
17
+
18
+ // Remove quotes if present
19
+ if (preg_match('/^"(.*)"$/', $value, $matches)) {
20
+ $value = $matches[1];
21
+ } elseif (preg_match("/^'(.*)'$/", $value, $matches)) {
22
+ $value = $matches[1];
23
+ }
24
+
25
+ if (!array_key_exists($name, $_ENV)) {
26
+ $_ENV[$name] = $value;
27
+ }
28
+ }
29
+ return true;
30
+ }
31
+
32
+ // Load .env file
33
+ if (file_exists(__DIR__ . '/.env')) {
34
+ loadEnv(__DIR__ . '/.env');
35
+ } else {
36
+ // Try to load from .env.example as fallback
37
+ if (file_exists(__DIR__ . '/.env.example')) {
38
+ loadEnv(__DIR__ . '/.env.example');
39
+ }
40
+ }
41
+
42
  // Configuration management class
43
  class StorageConfig {
44
  public static function getUsers() {
45
+ // Default users if no env variables found
46
+ $defaultUsers = [
47
+ 'PS01' => 'password123',
48
+ 'PS02' => 'password456',
49
+ 'admin' => 'admin123'
50
+ ];
51
+
52
  $users = [];
53
  $i = 1;
54
  while (true) {
 
62
  $users[$username] = $password;
63
  $i++;
64
  }
65
+
66
+ // If no users found in env, use defaults
67
+ return empty($users) ? $defaultUsers : $users;
68
  }
69
 
70
  public static function getStorageType() {