v0.9.4 bugs fixes
This commit is contained in:
61
.env.example
61
.env.example
@@ -1,15 +1,33 @@
|
||||
# jama Configuration
|
||||
# ─────────────────────────────────────────────────────────────
|
||||
# jama — Configuration
|
||||
# just another messaging app
|
||||
#
|
||||
# Copy this file to .env and customize before first run.
|
||||
# ─────────────────────────────────────────────────────────────
|
||||
|
||||
# Timezone — must match your host timezone (e.g. America/Toronto, Europe/London, Asia/Tokyo)
|
||||
# Run 'timedatectl' on your host to find the correct value
|
||||
TZ=UTC
|
||||
# Copy this file to .env and customize
|
||||
# Project name — used as the Docker container name.
|
||||
# If you run multiple jama instances on the same host, give each a unique name.
|
||||
PROJECT_NAME=jama
|
||||
|
||||
# Image version to run (set by build.sh, or use 'latest')
|
||||
JAMA_VERSION=0.9.3
|
||||
JAMA_VERSION=0.9.4
|
||||
|
||||
# Default admin credentials (used on FIRST RUN only)
|
||||
# App port — the host port Docker maps to the container
|
||||
PORT=3000
|
||||
|
||||
# Timezone — must match your host timezone
|
||||
# Run 'timedatectl' on Linux or 'ls /usr/share/zoneinfo' to find your value
|
||||
# Examples: America/Toronto, Europe/London, Asia/Tokyo
|
||||
TZ=UTC
|
||||
|
||||
# ── App ───────────────────────────────────────────────────────
|
||||
# App name (can also be changed in the Settings UI after first run)
|
||||
APP_NAME=jama
|
||||
|
||||
# Default public group name (created on first run only)
|
||||
DEFCHAT_NAME=General Chat
|
||||
|
||||
# ── Admin credentials (used on FIRST RUN only) ────────────────
|
||||
ADMIN_NAME=Admin User
|
||||
ADMIN_EMAIL=admin@jama.local
|
||||
ADMIN_PASS=Admin@1234
|
||||
@@ -17,25 +35,22 @@ ADMIN_PASS=Admin@1234
|
||||
# Default password for bulk-imported users (when no password is set in CSV)
|
||||
USER_PASS=user@1234
|
||||
|
||||
# Set to true to reset admin password to ADMIN_PASS on every restart
|
||||
# WARNING: Leave false in production - shows a warning on login page when true
|
||||
# Set to true to reset the admin password to ADMIN_PASS on every restart.
|
||||
# WARNING: Leave false in production — shows a warning banner on the login page when true.
|
||||
ADMPW_RESET=false
|
||||
|
||||
# JWT secret - change this to a random string in production!
|
||||
# ── Security ──────────────────────────────────────────────────
|
||||
# JWT secret — change this to a long random string in production!
|
||||
# Generate one: openssl rand -hex 32
|
||||
JWT_SECRET=changeme_super_secret_jwt_key_change_in_production
|
||||
|
||||
# Database encryption key (SQLCipher AES-256)
|
||||
# Generate a strong random key: openssl rand -hex 32
|
||||
# IMPORTANT: If you are upgrading from an unencrypted install, run the
|
||||
# migration script first: node scripts/encrypt-db.js
|
||||
# Leave blank to run without encryption (not recommended for production)
|
||||
# Generate a strong key: openssl rand -hex 32
|
||||
# Leave blank to run without encryption (not recommended for production).
|
||||
#
|
||||
# IMPORTANT — upgrading an existing unencrypted install:
|
||||
# 1. docker compose down
|
||||
# 2. Find your DB: docker volume inspect <project>_jama_db
|
||||
# 3. node backend/scripts/encrypt-db.js --db /path/to/jama.db --key YOUR_KEY
|
||||
# 4. Add DB_KEY=YOUR_KEY here, then: ./build.sh && docker compose up -d
|
||||
DB_KEY=
|
||||
|
||||
# App port (default 3000)
|
||||
PORT=3000
|
||||
|
||||
# App name (can also be changed in Settings UI)
|
||||
|
||||
# Default public group name (created on first run only)
|
||||
DEFCHAT_NAME=General Chat
|
||||
APP_NAME=jama
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "jama-backend",
|
||||
"version": "0.9.3",
|
||||
"version": "0.9.4",
|
||||
"description": "TeamChat backend server",
|
||||
"main": "src/index.js",
|
||||
"scripts": {
|
||||
|
||||
@@ -28,9 +28,14 @@ function getDb() {
|
||||
} else {
|
||||
console.warn('[DB] WARNING: DB_KEY not set — database is unencrypted');
|
||||
}
|
||||
db.pragma('journal_mode = WAL');
|
||||
const journalMode = db.pragma('journal_mode = WAL', { simple: true });
|
||||
if (journalMode !== 'wal') {
|
||||
console.warn(`[DB] WARNING: journal_mode is '${journalMode}', expected 'wal' — performance may be degraded`);
|
||||
}
|
||||
db.pragma('synchronous = NORMAL'); // safe with WAL, faster than FULL
|
||||
db.pragma('cache_size = -8000'); // 8MB page cache
|
||||
db.pragma('foreign_keys = ON');
|
||||
console.log(`[DB] Opened database at ${DB_PATH}`);
|
||||
console.log(`[DB] Opened database at ${DB_PATH} (journal=${journalMode})`);
|
||||
}
|
||||
return db;
|
||||
}
|
||||
|
||||
@@ -70,12 +70,10 @@ router.post('/subscribe', authMiddleware, (req, res) => {
|
||||
return res.status(400).json({ error: 'Invalid subscription' });
|
||||
}
|
||||
const db = getDb();
|
||||
// Use DELETE+INSERT to avoid relying on any specific UNIQUE constraint
|
||||
// (existing DBs may have different schemas for this table)
|
||||
const delStmt = db.prepare('DELETE FROM push_subscriptions WHERE endpoint = ?');
|
||||
const insStmt = db.prepare('INSERT INTO push_subscriptions (user_id, endpoint, p256dh, auth) VALUES (?, ?, ?, ?)');
|
||||
delStmt.run(endpoint);
|
||||
insStmt.run(req.user.id, endpoint, keys.p256dh, keys.auth);
|
||||
const device = req.device || 'desktop';
|
||||
// Delete any existing subscription for this user+device or this endpoint, then insert fresh
|
||||
db.prepare('DELETE FROM push_subscriptions WHERE endpoint = ? OR (user_id = ? AND device = ?)').run(endpoint, req.user.id, device);
|
||||
db.prepare('INSERT INTO push_subscriptions (user_id, device, endpoint, p256dh, auth) VALUES (?, ?, ?, ?, ?)').run(req.user.id, device, endpoint, keys.p256dh, keys.auth);
|
||||
res.json({ success: true });
|
||||
});
|
||||
|
||||
|
||||
2
build.sh
2
build.sh
@@ -13,7 +13,7 @@
|
||||
# ─────────────────────────────────────────────────────────────
|
||||
set -euo pipefail
|
||||
|
||||
VERSION="${1:-0.9.3}"
|
||||
VERSION="${1:-0.9.4}"
|
||||
ACTION="${2:-}"
|
||||
REGISTRY="${REGISTRY:-}"
|
||||
IMAGE_NAME="jama"
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
jama:
|
||||
image: jama:${JAMA_VERSION:-latest}
|
||||
container_name: jama
|
||||
container_name: ${PROJECT_NAME:-jama}
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "${PORT:-3000}:3000"
|
||||
@@ -16,9 +14,9 @@ services:
|
||||
- USER_PASS=${USER_PASS:-user@1234}
|
||||
- ADMPW_RESET=${ADMPW_RESET:-false}
|
||||
- JWT_SECRET=${JWT_SECRET:-changeme_super_secret_jwt_key_2024}
|
||||
- DB_KEY=${DB_KEY}
|
||||
- APP_NAME=${APP_NAME:-jama}
|
||||
- DEFCHAT_NAME=${DEFCHAT_NAME:-General Chat}
|
||||
- DB_KEY=${DB_KEY:-}
|
||||
volumes:
|
||||
- jama_db:/app/data
|
||||
- jama_uploads:/app/uploads
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "jama-frontend",
|
||||
"version": "0.9.3",
|
||||
"version": "0.9.4",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
|
||||
@@ -6,6 +6,7 @@ import { useAuth } from '../contexts/AuthContext.jsx';
|
||||
import { useToast } from '../contexts/ToastContext.jsx';
|
||||
import { useSocket } from '../contexts/SocketContext.jsx';
|
||||
import './ChatWindow.css';
|
||||
import GroupInfoModal from './GroupInfoModal.jsx';
|
||||
|
||||
export default function ChatWindow({ group, onBack, onGroupUpdated, onDirectMessage, onlineUserIds = new Set() }) {
|
||||
const { user: currentUser } = useAuth();
|
||||
@@ -17,6 +18,7 @@ export default function ChatWindow({ group, onBack, onGroupUpdated, onDirectMess
|
||||
const [hasMore, setHasMore] = useState(false);
|
||||
const [typing, setTyping] = useState([]);
|
||||
const [iconGroupInfo, setIconGroupInfo] = useState('');
|
||||
const [showInfo, setShowInfo] = useState(false);
|
||||
const [isMobile, setIsMobile] = useState(window.innerWidth < 768);
|
||||
|
||||
const messagesEndRef = useRef(null);
|
||||
@@ -231,7 +233,7 @@ export default function ChatWindow({ group, onBack, onGroupUpdated, onDirectMess
|
||||
{!isDirect && (
|
||||
<button
|
||||
className="btn-icon"
|
||||
onClick={() => window.dispatchEvent(new CustomEvent('jama:group-info', { detail: group }))}
|
||||
onClick={() => setShowInfo(true)}
|
||||
title="Group info"
|
||||
>
|
||||
{iconGroupInfo ? (
|
||||
@@ -293,5 +295,15 @@ export default function ChatWindow({ group, onBack, onGroupUpdated, onDirectMess
|
||||
<MessageInput group={group} currentUser={currentUser} onSend={handleSend} socket={socket} />
|
||||
)}
|
||||
</div>
|
||||
|
||||
{showInfo && (
|
||||
<GroupInfoModal
|
||||
group={group}
|
||||
onClose={() => setShowInfo(false)}
|
||||
onUpdated={(updatedGroup) => { setShowInfo(false); onGroupUpdated && onGroupUpdated(updatedGroup); }}
|
||||
onBack={() => setShowInfo(false)}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user