mirror of
https://github.com/sky-systems/sky_phone.git
synced 2026-08-28 17:01:18 +00:00
fix LB Phone migration and German locale
This commit is contained in:
@@ -0,0 +1,53 @@
|
||||
import { readFileSync } from 'node:fs'
|
||||
|
||||
import { describe, expect, it } from 'vitest'
|
||||
|
||||
const migration = readFileSync(
|
||||
new URL(
|
||||
'../../sky_phone/source/server/lb_phone_migration.lua',
|
||||
import.meta.url,
|
||||
),
|
||||
'utf8',
|
||||
)
|
||||
const config = readFileSync(
|
||||
new URL('../../sky_phone/config/config.lua', import.meta.url),
|
||||
'utf8',
|
||||
)
|
||||
|
||||
describe('LB Phone social migration contract', () => {
|
||||
it('reruns the repaired social domains and maps active LB profiles to Sky accounts', () => {
|
||||
expect(migration).toMatch(
|
||||
/local domain_versions = \{[\s\S]*?picstagram = 2,[\s\S]*?flipTok = 2,[\s\S]*?feather = 2,/,
|
||||
)
|
||||
expect(migration).toContain(
|
||||
'local function prepare_social_profile_accounts',
|
||||
)
|
||||
expect(migration).toContain('preferred_entry_by_owner')
|
||||
expect(migration).toContain('owner.`account_id`')
|
||||
expect(migration).toContain(
|
||||
'move_profile(existing, preferred_entry, owner_account_id)',
|
||||
)
|
||||
})
|
||||
|
||||
it('refreshes device sessions when the active LB account changed', () => {
|
||||
expect(migration).toMatch(
|
||||
/INSERT INTO `sky_phone_picstagram_sessions`[\s\S]*?ON DUPLICATE KEY UPDATE `profile_id` = VALUES\(`profile_id`\)/,
|
||||
)
|
||||
expect(migration).toMatch(
|
||||
/INSERT INTO `sky_phone_fliptok_sessions`[\s\S]*?ON DUPLICATE KEY UPDATE `profile_id` = VALUES\(`profile_id`\)/,
|
||||
)
|
||||
})
|
||||
|
||||
it('imports LB Tinder data into the Flare domain', () => {
|
||||
expect(config).toMatch(/Domains = \{[\s\S]*?flare = true,/)
|
||||
expect(migration).toContain('local function run_flare(dry_run)')
|
||||
expect(migration).toContain('source_table("tinder_accounts")')
|
||||
expect(migration).toContain('source_table("tinder_swipes")')
|
||||
expect(migration).toContain('INSERT IGNORE INTO `sky_phone_flare_profiles`')
|
||||
expect(migration).toContain(
|
||||
'INSERT IGNORE INTO `sky_phone_flare_profile_photos`',
|
||||
)
|
||||
expect(migration).toContain('INSERT IGNORE INTO `sky_phone_flare_swipes`')
|
||||
expect(migration).toContain('INSERT IGNORE INTO `sky_phone_flare_matches`')
|
||||
})
|
||||
})
|
||||
@@ -73,20 +73,20 @@ function tokenizeLua(source: string): LuaToken[] {
|
||||
return tokens
|
||||
}
|
||||
|
||||
function collectLuaLocalePaths(source: string): Set<string> {
|
||||
function collectLuaLocaleValues(source: string): Map<string, string> {
|
||||
const tokens = tokenizeLua(source)
|
||||
let position =
|
||||
tokens.findIndex(
|
||||
(token, index) => token.kind === '=' && tokens[index + 1]?.kind === '{',
|
||||
) + 1
|
||||
const paths = new Set<string>()
|
||||
const values = new Map<string, string>()
|
||||
|
||||
function parseValue(path: string[]): void {
|
||||
if (tokens[position]?.kind === '{') {
|
||||
parseTable(path)
|
||||
return
|
||||
}
|
||||
if (path.length) paths.add(path.join('.'))
|
||||
if (path.length) values.set(path.join('.'), tokens[position]?.value ?? '')
|
||||
position += 1
|
||||
}
|
||||
|
||||
@@ -118,7 +118,11 @@ function collectLuaLocalePaths(source: string): Set<string> {
|
||||
}
|
||||
|
||||
parseTable([])
|
||||
return paths
|
||||
return values
|
||||
}
|
||||
|
||||
function collectPlaceholders(value: string): string[] {
|
||||
return [...new Set(value.match(/\{[A-Za-z0-9_]+\}/g) ?? [])].sort()
|
||||
}
|
||||
|
||||
function collectDefaultLocalePaths(source: string): Set<string> {
|
||||
@@ -196,7 +200,9 @@ function collectFrontendFiles(directory: string): string[] {
|
||||
}
|
||||
|
||||
describe('phone locale contract', () => {
|
||||
const englishPaths = collectLuaLocalePaths(englishLocaleSource)
|
||||
const englishValues = collectLuaLocaleValues(englishLocaleSource)
|
||||
const germanValues = collectLuaLocaleValues(germanLocaleSource)
|
||||
const englishPaths = new Set(englishValues.keys())
|
||||
|
||||
it('keeps every bundled frontend fallback in en.lua', () => {
|
||||
const missing = [...collectDefaultLocalePaths(phoneStoreSource)].filter(
|
||||
@@ -243,8 +249,78 @@ describe('phone locale contract', () => {
|
||||
})
|
||||
|
||||
it('keeps German structurally aligned with English', () => {
|
||||
const germanPaths = collectLuaLocalePaths(germanLocaleSource)
|
||||
const germanPaths = new Set(germanValues.keys())
|
||||
|
||||
expect([...germanPaths].sort()).toEqual([...englishPaths].sort())
|
||||
})
|
||||
|
||||
it('keeps German interpolation placeholders aligned with English', () => {
|
||||
const mismatches = [...englishValues].flatMap(([path, englishValue]) => {
|
||||
const germanValue = germanValues.get(path)
|
||||
return germanValue !== undefined &&
|
||||
JSON.stringify(collectPlaceholders(germanValue)) !==
|
||||
JSON.stringify(collectPlaceholders(englishValue))
|
||||
? [
|
||||
`${path}: ${collectPlaceholders(englishValue).join(', ')} != ${collectPlaceholders(germanValue).join(', ')}`,
|
||||
]
|
||||
: []
|
||||
})
|
||||
|
||||
expect(mismatches).toEqual([])
|
||||
})
|
||||
|
||||
it('keeps standard app names German and custom game names unchanged', () => {
|
||||
const standardAppNames = {
|
||||
health: 'Gesundheit',
|
||||
messages: 'Nachrichten',
|
||||
companies: 'Unternehmen',
|
||||
phone: 'Telefon',
|
||||
radio: 'Funk',
|
||||
billing: 'Rechnungen',
|
||||
house: 'Haus',
|
||||
calculator: 'Rechner',
|
||||
camera: 'Kamera',
|
||||
calendar: 'Kalender',
|
||||
clock: 'Uhr',
|
||||
localPages: 'Lokale Seiten',
|
||||
map: 'Karte',
|
||||
weather: 'Wetter',
|
||||
music: 'Musik',
|
||||
notes: 'Notizen',
|
||||
photos: 'Fotos',
|
||||
settings: 'Einstellungen',
|
||||
}
|
||||
|
||||
for (const [app, name] of Object.entries(standardAppNames)) {
|
||||
expect(germanValues.get(`Nui.Apps.${app}.name`), app).toBe(name)
|
||||
}
|
||||
|
||||
for (const app of [
|
||||
'snake',
|
||||
'memory',
|
||||
'numberMerge',
|
||||
'minesweeper',
|
||||
'towerStack',
|
||||
'skyFlappy',
|
||||
'neonDrop',
|
||||
]) {
|
||||
const path = `Nui.Apps.${app}.name`
|
||||
expect(germanValues.get(path), app).toBe(englishValues.get(path))
|
||||
}
|
||||
})
|
||||
|
||||
it('keeps common German UI terms semantically correct', () => {
|
||||
expect(germanValues.get('Nui.Apps.phone.cancelled')).toBe('Abgebrochen')
|
||||
expect(germanValues.get('Nui.Apps.flare.interests')).toBe('Interessen')
|
||||
expect(germanValues.get('Nui.Apps.picstagram.emptyFeed')).toBe(
|
||||
'Dein Feed ist ruhig',
|
||||
)
|
||||
expect(germanValues.get('Nui.Apps.clock.lap')).toBe('Runde')
|
||||
expect(germanValues.get('Nui.Apps.easyShare.incoming')).toBe(
|
||||
'Eingehende Freigabe',
|
||||
)
|
||||
expect(germanValues.get('Nui.Apps.settings.phoneScale')).toBe(
|
||||
'Telefongröße',
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -142,6 +142,19 @@ describe('FeatherApp Sky UI contract', () => {
|
||||
expect(source).not.toContain('feather-feed-add')
|
||||
})
|
||||
|
||||
it('keeps profile suggestion content styles off the follow button', () => {
|
||||
expect(source).toContain('class="feather-profile-suggestion__profile"')
|
||||
expect(source).toMatch(
|
||||
/\.feather-app\.feather-app--active \.feather-profile-suggestion__profile\s*\{[^}]*width:\s*100%/s,
|
||||
)
|
||||
expect(source).not.toContain(
|
||||
'.feather-app.feather-app--active .feather-profile-suggestion > button',
|
||||
)
|
||||
expect(source).not.toContain(
|
||||
'.dark.feather-app .feather-profile-suggestion > button',
|
||||
)
|
||||
})
|
||||
|
||||
it('keeps owner actions in the navbar and removes the profile media tab', () => {
|
||||
const profileStart = source.indexOf('class="feather-profile"')
|
||||
const tabsStart = source.indexOf(
|
||||
|
||||
+3
-1
@@ -414,7 +414,9 @@ The importer:
|
||||
- Can remove migration-created Sky Phone data with `remove`
|
||||
- Reports unsupported source records instead of forcing them into incompatible Sky Phone structures
|
||||
|
||||
Supported domains include devices, settings, alarms, contacts, blocked numbers, calls, messages, photos, notes, wallet, voice memos, Picstagram, Mail, map markers, compatible DarkChat data, FlipTok, and Feather.
|
||||
For Picstagram, FlipTok, and Feather, the active LB Phone login is attached to the migrated player's Sky Cloud account. If LB has no active-login row, the oldest mapped profile is used. Additional social profiles remain separate, and a normal import automatically runs versioned ownership repairs for older Sky Phone migrations.
|
||||
|
||||
Supported domains include devices, settings, alarms, contacts, blocked numbers, calls, messages, photos, notes, wallet, voice memos, Picstagram, Mail, map markers, compatible DarkChat data, FlipTok, Feather, and Flare (LB Tinder profiles, photos, swipes, and mutual matches).
|
||||
|
||||
The migration command is server-console only.
|
||||
|
||||
|
||||
@@ -1439,6 +1439,7 @@ if IsDuplicityVersion() then
|
||||
darkChat = true,
|
||||
flipTok = true,
|
||||
feather = true,
|
||||
flare = true,
|
||||
},
|
||||
}
|
||||
end
|
||||
|
||||
+376
-376
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user