Add public Android APK download
This commit is contained in:
@@ -18,3 +18,4 @@ MAIL_USER=
|
|||||||
MAIL_PASS=
|
MAIL_PASS=
|
||||||
MAIL_FROM=noreply@linkedsign.local
|
MAIL_FROM=noreply@linkedsign.local
|
||||||
FRONTEND_URL=http://localhost:5173
|
FRONTEND_URL=http://localhost:5173
|
||||||
|
ANDROID_APK_PATH=
|
||||||
|
|||||||
@@ -40,6 +40,8 @@ const env = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
frontendUrl: process.env.FRONTEND_URL || 'http://localhost:5173',
|
frontendUrl: process.env.FRONTEND_URL || 'http://localhost:5173',
|
||||||
|
androidApkPath:
|
||||||
|
process.env.ANDROID_APK_PATH || path.resolve(process.cwd(), '..', 'android', 'apk', 'LinkedSign-debug.apk'),
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = env;
|
module.exports = env;
|
||||||
|
|||||||
@@ -0,0 +1,14 @@
|
|||||||
|
const downloadsService = require('./downloads.service');
|
||||||
|
|
||||||
|
const downloadAndroidApk = async (req, res, next) => {
|
||||||
|
try {
|
||||||
|
const { filePath, fileName } = await downloadsService.getAndroidApk();
|
||||||
|
return res.download(filePath, fileName);
|
||||||
|
} catch (error) {
|
||||||
|
return next(error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
downloadAndroidApk,
|
||||||
|
};
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
const express = require('express');
|
||||||
|
const downloadsController = require('./downloads.controller');
|
||||||
|
|
||||||
|
const router = express.Router();
|
||||||
|
|
||||||
|
router.get('/android-apk', downloadsController.downloadAndroidApk);
|
||||||
|
|
||||||
|
module.exports = router;
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
const fs = require('fs/promises');
|
||||||
|
const path = require('path');
|
||||||
|
const env = require('../../config/env');
|
||||||
|
|
||||||
|
const getAndroidApk = async () => {
|
||||||
|
const filePath = env.androidApkPath;
|
||||||
|
|
||||||
|
try {
|
||||||
|
await fs.access(filePath);
|
||||||
|
} catch {
|
||||||
|
const error = new Error('Android APK not found.');
|
||||||
|
error.statusCode = 404;
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
filePath,
|
||||||
|
fileName: path.basename(filePath),
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
getAndroidApk,
|
||||||
|
};
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
const express = require('express');
|
const express = require('express');
|
||||||
const authRoutes = require('../modules/auth/auth.routes');
|
const authRoutes = require('../modules/auth/auth.routes');
|
||||||
const certificatesRoutes = require('../modules/certificates/certificates.routes');
|
const certificatesRoutes = require('../modules/certificates/certificates.routes');
|
||||||
|
const downloadsRoutes = require('../modules/downloads/downloads.routes');
|
||||||
const documentsRoutes = require('../modules/documents/documents.routes');
|
const documentsRoutes = require('../modules/documents/documents.routes');
|
||||||
const signaturesRoutes = require('../modules/signatures/signatures.routes');
|
const signaturesRoutes = require('../modules/signatures/signatures.routes');
|
||||||
const usersRoutes = require('../modules/users/users.routes');
|
const usersRoutes = require('../modules/users/users.routes');
|
||||||
@@ -10,6 +11,7 @@ const router = express.Router();
|
|||||||
|
|
||||||
router.use('/auth', authRoutes);
|
router.use('/auth', authRoutes);
|
||||||
router.use('/certificates', certificatesRoutes);
|
router.use('/certificates', certificatesRoutes);
|
||||||
|
router.use('/downloads', downloadsRoutes);
|
||||||
router.use('/documents', documentsRoutes);
|
router.use('/documents', documentsRoutes);
|
||||||
router.use('/signatures', signaturesRoutes);
|
router.use('/signatures', signaturesRoutes);
|
||||||
router.use('/users', usersRoutes);
|
router.use('/users', usersRoutes);
|
||||||
|
|||||||
@@ -391,6 +391,9 @@ select {
|
|||||||
.auth-link { text-align: center; margin-top: 20px; font-size: 13px; color: var(--gray-500); }
|
.auth-link { text-align: center; margin-top: 20px; font-size: 13px; color: var(--gray-500); }
|
||||||
.auth-link a { color: var(--primary); font-weight: 600; text-decoration: none; }
|
.auth-link a { color: var(--primary); font-weight: 600; text-decoration: none; }
|
||||||
.auth-link a:hover { text-decoration: underline; }
|
.auth-link a:hover { text-decoration: underline; }
|
||||||
|
.auth-download-btn {
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
/* ─── Form fields ────────────────────────────────────────────── */
|
/* ─── Form fields ────────────────────────────────────────────── */
|
||||||
.field { display: flex; flex-direction: column; gap: 5px; }
|
.field { display: flex; flex-direction: column; gap: 5px; }
|
||||||
|
|||||||
@@ -9,6 +9,8 @@ export default function LoginPage() {
|
|||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const [form, setForm] = useState({ email: '', password: '' });
|
const [form, setForm] = useState({ email: '', password: '' });
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
|
const apiBaseUrl = (import.meta.env.VITE_API_URL || 'http://localhost:4000').replace(/\/$/, '');
|
||||||
|
const androidApkUrl = `${apiBaseUrl}/downloads/android-apk`;
|
||||||
|
|
||||||
const handleChange = (e) => setForm((f) => ({ ...f, [e.target.name]: e.target.value }));
|
const handleChange = (e) => setForm((f) => ({ ...f, [e.target.name]: e.target.value }));
|
||||||
|
|
||||||
@@ -54,6 +56,9 @@ export default function LoginPage() {
|
|||||||
<button type="submit" className="btn btn-primary btn-full" disabled={loading}>
|
<button type="submit" className="btn btn-primary btn-full" disabled={loading}>
|
||||||
{loading ? 'Ingresando...' : 'Iniciar sesión'}
|
{loading ? 'Ingresando...' : 'Iniciar sesión'}
|
||||||
</button>
|
</button>
|
||||||
|
<a className="btn btn-secondary btn-full auth-download-btn" href={androidApkUrl}>
|
||||||
|
Descargar app Android
|
||||||
|
</a>
|
||||||
</form>
|
</form>
|
||||||
<p className="auth-link">
|
<p className="auth-link">
|
||||||
¿No tienes cuenta? <Link to="/register">Registrarse</Link>
|
¿No tienes cuenta? <Link to="/register">Registrarse</Link>
|
||||||
|
|||||||
Reference in New Issue
Block a user