Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 10 additions & 6 deletions worklenz-backend/src/controllers/auth-controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -114,8 +114,11 @@ export default class AuthController extends WorklenzControllerBase {
public static async reset_password(req: IWorkLenzRequest, res: IWorkLenzResponse) {
const {email} = req.body;

const q = `SELECT id, email, google_id, password FROM users WHERE email = $1;`;
const result = await db.query(q, [email || null]);
// Normalize email to lowercase for case-insensitive comparison
const normalizedEmail = email ? email.toLowerCase().trim() : null;

const q = `SELECT id, email, google_id, password FROM users WHERE LOWER(email) = $1;`;
const result = await db.query(q, [normalizedEmail]);

if (!result.rowCount)
return res.status(200).send(new ServerResponse(false, null, "Account does not exists!"));
Expand Down Expand Up @@ -297,15 +300,16 @@ export default class AuthController extends WorklenzControllerBase {
}

// Check for existing local account
const localAccountResult = await db.query("SELECT 1 FROM users WHERE email = $1 AND password IS NOT NULL AND is_deleted IS FALSE;", [profile.email]);
const normalizedProfileEmail = profile.email.toLowerCase().trim();
const localAccountResult = await db.query("SELECT 1 FROM users WHERE LOWER(email) = $1 AND password IS NOT NULL AND is_deleted IS FALSE;", [normalizedProfileEmail]);
if (localAccountResult.rowCount) {
return res.status(400).send(new ServerResponse(false, null, `No Google account exists for email ${profile.email}.`));
}

// Check if user exists
const userResult = await db.query(
"SELECT id, google_id, name, email, active_team FROM users WHERE google_id = $1 OR email = $2;",
[profile.sub, profile.email]
"SELECT id, google_id, name, email, active_team FROM users WHERE google_id = $1 OR LOWER(email) = $2;",
[profile.sub, normalizedProfileEmail]
);

let user: any;
Expand All @@ -317,7 +321,7 @@ export default class AuthController extends WorklenzControllerBase {
const googleUserData = {
id: profile.sub,
displayName: profile.name,
email: profile.email,
email: normalizedProfileEmail,
picture: profile.picture
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,15 @@ async function handleLogin(req: Request, email: string, password: string, done:
}

try {
// Normalize email to lowercase for case-insensitive comparison
const normalizedEmail = email.toLowerCase().trim();

const q = `SELECT id, email, google_id, password
FROM users
WHERE email = $1
WHERE LOWER(email) = $1
AND google_id IS NULL
AND is_deleted IS FALSE;`;
const result = await db.query(q, [email]);
const result = await db.query(q, [normalizedEmail]);

const [data] = result.rows;

Expand All @@ -33,7 +36,7 @@ async function handleLogin(req: Request, email: string, password: string, done:

const passwordMatch = bcrypt.compareSync(password, data.password);

if (passwordMatch && email === data.email) {
if (passwordMatch) {
delete data.password;
const successMsg = "User successfully logged in";
req.flash(SUCCESS_KEY, successMsg);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,21 +13,21 @@ async function isGoogleAccountFound(email: string) {
const q = `
SELECT 1
FROM users
WHERE email = $1
WHERE LOWER(email) = $1
AND google_id IS NOT NULL;
`;
const result = await db.query(q, [email]);
const result = await db.query(q, [email.toLowerCase().trim()]);
return !!result.rowCount;
}

async function isAccountDeactivated(email: string) {
const q = `
SELECT 1
FROM users
WHERE email = $1
WHERE LOWER(email) = $1
AND is_deleted = TRUE;
`;
const result = await db.query(q, [email]);
const result = await db.query(q, [email.toLowerCase().trim()]);
return !!result.rowCount;
}

Expand All @@ -41,7 +41,7 @@ async function registerUser(password: string, team_id: string, name: string, tea
const body = {
name,
team_name,
email,
email: email.toLowerCase().trim(),
password: encryptedPassword,
timezone,
invited_team_id: teamId,
Expand Down
11 changes: 0 additions & 11 deletions worklenz-backend/src/views/_tawk-to.pug

This file was deleted.

6 changes: 6 additions & 0 deletions worklenz-frontend/public/locales/alb/common.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,12 @@
"trial-badge-hours": "{{hours}} orë të mbetura",
"trial-alert-admin-note": "Ju mund të aksesoni ende Qendrën e Administrimit për të menaxhuar abonimin tuaj",
"trial-alert-dismiss": "Hidhe për sot",
"switch-team-to-continue": "Ndërro skuadrën për të vazhduar",
"current-team": "Skuadra aktuale",
"select-team": "Zgjidh skuadrën",
"owned-by": "Në pronësi të",
"switch-team-active-subscription": "Kaloni në një skuadër me një abonim aktiv për të vazhduar punën",
"or": "ose",
"license-expiring-soon": "Licenca juaj skadon në {{days}} ditë",
"license-expiring-soon_plural": "Licenca juaj skadon në {{days}} ditë",
"license-expiring-today": "Licenca juaj skadon sot!",
Expand Down
6 changes: 6 additions & 0 deletions worklenz-frontend/public/locales/de/common.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,12 @@
"trial-badge-hours": "{{hours}}h übrig",
"trial-alert-admin-note": "Sie können weiterhin auf das Admin Center zugreifen, um Ihr Abonnement zu verwalten",
"trial-alert-dismiss": "Für heute ausblenden",
"switch-team-to-continue": "Team wechseln zum Fortfahren",
"current-team": "Aktuelles Team",
"select-team": "Team auswählen",
"owned-by": "Gehört",
"switch-team-active-subscription": "Wechseln Sie zu einem Team mit einem aktiven Abonnement, um weiterzuarbeiten",
"or": "oder",
"license-expiring-soon": "Ihre Lizenz läuft in {{days}} Tag ab",
"license-expiring-soon_plural": "Ihre Lizenz läuft in {{days}} Tagen ab",
"license-expiring-today": "Ihre Lizenz läuft heute ab!",
Expand Down
6 changes: 6 additions & 0 deletions worklenz-frontend/public/locales/en/common.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,12 @@
"trial-badge-hours": "{{hours}}h left",
"trial-alert-admin-note": "You can still access the Admin Center to manage your subscription",
"trial-alert-dismiss": "Dismiss for today",
"switch-team-to-continue": "Switch Team to Continue",
"current-team": "Current Team",
"select-team": "Select Team",
"owned-by": "Owned by",
"switch-team-active-subscription": "Switch to a team with an active subscription to continue working",
"or": "or",
"license-expiring-soon": "Your license expires in {{days}} day",
"license-expiring-soon_plural": "Your license expires in {{days}} days",
"license-expiring-today": "Your license expires today!",
Expand Down
6 changes: 6 additions & 0 deletions worklenz-frontend/public/locales/es/common.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,12 @@
"trial-badge-hours": "{{hours}}h restantes",
"trial-alert-admin-note": "Aún puede acceder al Centro de administración para gestionar su suscripción",
"trial-alert-dismiss": "Descartar por hoy",
"switch-team-to-continue": "Cambiar equipo para continuar",
"current-team": "Equipo actual",
"select-team": "Seleccionar equipo",
"owned-by": "Propiedad de",
"switch-team-active-subscription": "Cambie a un equipo con una suscripción activa para continuar trabajando",
"or": "o",
"license-expiring-soon": "Su licencia expira en {{days}} día",
"license-expiring-soon_plural": "Su licencia expira en {{days}} días",
"license-expiring-today": "¡Su licencia expira hoy!",
Expand Down
6 changes: 6 additions & 0 deletions worklenz-frontend/public/locales/pt/common.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,12 @@
"trial-badge-hours": "{{hours}}h restantes",
"trial-alert-admin-note": "Você ainda pode acessar o Centro de administração para gerenciar sua assinatura",
"trial-alert-dismiss": "Dispensar por hoje",
"switch-team-to-continue": "Trocar equipe para continuar",
"current-team": "Equipe atual",
"select-team": "Selecionar equipe",
"owned-by": "Propriedade de",
"switch-team-active-subscription": "Mude para uma equipe com uma assinatura ativa para continuar trabalhando",
"or": "ou",
"license-expiring-soon": "Sua licença expira em {{days}} dia",
"license-expiring-soon_plural": "Sua licença expira em {{days}} dias",
"license-expiring-today": "Sua licença expira hoje!",
Expand Down
6 changes: 6 additions & 0 deletions worklenz-frontend/public/locales/zh/common.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,12 @@
"trial-badge-hours": "剩余{{hours}}小时",
"trial-alert-admin-note": "您仍可以访问管理中心管理您的订阅",
"trial-alert-dismiss": "今日暂不提醒",
"switch-team-to-continue": "切换团队以继续",
"current-team": "当前团队",
"select-team": "选择团队",
"owned-by": "拥有者",
"switch-team-active-subscription": "切换到有有效订阅的团队以继续工作",
"or": "或",
"license-expiring-soon": "您的许可证还有 {{days}} 天到期",
"license-expiring-soon_plural": "您的许可证还有 {{days}} 天到期",
"license-expiring-today": "您的许可证今天到期!",
Expand Down
18 changes: 6 additions & 12 deletions worklenz-frontend/src/app/routes/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -74,21 +74,15 @@ export const LicenseExpiryGuard = memo(({ children }: GuardProps) => {
const currentSession = authService?.getCurrentSession();
const subscriptionType = currentSession?.subscription_type as ISUBSCRIPTION_TYPE;

// If license is expired and not on admin center, block the content entirely
// If license is expired and not on admin center, show modal overlay
if (showModal) {
return (
<div style={{ position: 'relative', height: '100vh', overflow: 'hidden' }}>
<div style={{
position: 'absolute',
inset: 0,
pointerEvents: 'none',
opacity: 0.3,
filter: 'blur(2px)'
}}>
{children}
</div>
<>
{/* Render children normally */}
{children}
{/* Show modal as an overlay */}
<LicenseExpiredModal open={true} subscriptionType={subscriptionType} />
</div>
</>
);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
.license-expired-modal-wrap .ant-modal-wrap {
z-index: 1050 !important;
}

.license-expired-modal-wrap .ant-modal-mask {
z-index: 1049 !important;
}

/* Ensure dropdowns in the modal appear above the modal */
.switch-team-dropdown {
z-index: 1060 !important;
}

/* Theme-aware dropdown styling */
.switch-team-dropdown .ant-dropdown-menu {
border-radius: 8px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
}

[data-theme="dark"] .switch-team-dropdown .ant-dropdown-menu {
background-color: #262626;
border: 1px solid #434343;
}

[data-theme="dark"] .switch-team-dropdown .ant-dropdown-menu-item {
color: #fff;
}

[data-theme="dark"] .switch-team-dropdown .ant-dropdown-menu-item:hover {
background-color: #303030;
}

/* Ensure the modal content is properly styled */
.license-expired-modal-wrap .ant-modal-content {
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.2);
}
Loading