Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix sync creating directories locally #285

Merged
merged 1 commit into from
Dec 26, 2024
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
4 changes: 2 additions & 2 deletions src/preload/client/files.ts
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,7 @@ export class FilesClient {
* are still needed as access check may be innaccurate or could change while
* app is running.
*/
ensureDir = async (directory: string): Promise<void> => {
ensureDir = async (directory: string, create = true): Promise<void> => {
try {
const dir = await stat(directory);
if (!dir.isDirectory()) {
Expand All @@ -247,7 +247,7 @@ export class FilesClient {
}
} catch (err: any) {
if (err.code !== "ENOENT") throw err;
await Files.mkdirp(directory);
if (create) await Files.mkdirp(directory);
}

// NOTE: Documentation suggests Windows may report ok here, but then choke
Expand Down
2 changes: 1 addition & 1 deletion src/preload/client/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ export function create(): IClient {
if (!client) {
const preferences = new PreferencesClient(settings);
const files = new FilesClient(settings);
const journals = new JournalsClient(db, files, preferences);
const journals = new JournalsClient(knex, files, preferences);
const documents = new DocumentsClient(db, knex, files, preferences);
const sync = new SyncClient(
db,
Expand Down
79 changes: 29 additions & 50 deletions src/preload/client/journals.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Database } from "better-sqlite3";
import { Knex } from "knex";
import path from "path";

import { IFilesClient } from "./files";
Expand All @@ -9,15 +9,13 @@ export type IJournalsClient = JournalsClient;

export class JournalsClient {
constructor(
private db: Database,
private knex: Knex,
private files: IFilesClient,
private preferences: IPreferencesClient,
) {}

list = async (): Promise<JournalResponse[]> => {
const journals = this.db
.prepare("select * from journals order by name")
.all();
const journals = await this.knex("journals").select("*").orderBy("name");

const archived = await this.preferences.get("ARCHIVED_JOURNALS");
journals.forEach((j) => {
Expand All @@ -34,71 +32,54 @@ export class JournalsClient {
};

index = async (journalName: string): Promise<JournalResponse> => {
// add to archived if not already present
const existing = await this.preferences.get(
`ARCHIVED_JOURNALS.${journalName}`,
);

if (existing == null) {
await this.preferences.set(`ARCHIVED_JOURNALS.${journalName}`, false);
}

this.db
.prepare(
"insert into journals (name, createdAt, updatedAt) values (:name, :createdAt, :updatedAt)",
)
.run({
name: journalName,
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
});

return this.db
.prepare("select * from journals where name = :name")
.get({ name: journalName });
const timestamp = new Date().toISOString();

await this.knex("journals").insert({
name: journalName,
createdAt: timestamp,
updatedAt: timestamp,
});

return await this.knex("journals").where("name", journalName).first();
};

rename = async (
// note: do not pass the full JournalResponse mobx object here; restructure
// it to just the name and archived fields
journal: { name: string; archived: boolean },
newName: string,
): Promise<JournalResponse> => {
newName = validateJournalName(newName);
await this.files.renameFolder(journal.name, newName);

this.db
.prepare(
"update journals set name = :newName, updatedAt = :updatedAt where name = :name",
)
.run({
name: journal.name,
newName,
updatedAt: new Date().toISOString(),
});

// todo: dumb; revert to having documents reference id instead of name
this.db
.prepare("update documents set journal = :newName where journal = :name")
.run({
name: journal.name,
newName,
});
const timestamp = new Date().toISOString();

await this.knex("journals")
.update({ name: newName, updatedAt: timestamp })
.where("name", journal.name);

await this.knex("documents")
.update({ journal: newName })
.where("journal", journal.name);

await this.preferences.delete(`ARCHIVED_JOURNALS.${journal.name}`);
await this.preferences.set(
`ARCHIVED_JOURNALS.${newName}`,
journal.archived,
);

return this.db
.prepare("select * from journals where name = :name")
.get({ name: newName });
return await this.knex("journals").where("name", newName).first();
};

remove = async (journal: string): Promise<JournalResponse[]> => {
// todo: Allow removing the last journal; handle this like first-time
// setup
if ((await this.list()).length === 1) {
const journals = await this.list();
if (journals.length === 1) {
throw new Error(
"Cannot delete the last journal. Create a new journal first.",
);
Expand All @@ -107,9 +88,7 @@ export class JournalsClient {
await this.files.removeFolder(journal);
await this.preferences.delete(`ARCHIVED_JOURNALS.${journal}`);

this.db
.prepare("delete from journals where name = :name")
.run({ name: journal });
await this.knex("journals").where("name", journal).delete();
return this.list();
};

Expand Down Expand Up @@ -139,7 +118,7 @@ export const validateJournalName = (name: string): string => {
throw new Error("Journal name cannot be '_attachments'.");
}

// Check for max length
// Ensure journal name is not too long
if (name.length > MAX_NAME_LENGTH) {
throw new Error(
`Journal name exceeds max length of ${MAX_NAME_LENGTH} characters.`,
Expand All @@ -148,12 +127,12 @@ export const validateJournalName = (name: string): string => {

let sanitized = decodeURIComponent(encodeURIComponent(name));

// Check for URL safety
// Check for URL safe characters
if (name !== sanitized) {
throw new Error("Journal name is not URL safe.");
}

// Ensure the name doesn't contain path traversal or invalid slashes
// Ensure the name does not contain path traversal characters or invalid slashes
sanitized = path.basename(name);
if (sanitized !== name) {
throw new Error("Journal name contains invalid path characters.");
Expand Down
3 changes: 2 additions & 1 deletion src/preload/client/sync.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,8 @@ export class SyncClient {
// Once we find at least one markdown file, we treat this directory
// as a journal
if (!(dirname in journals)) {
await this.files.ensureDir(dirname);
// probably unnecessary
await this.files.ensureDir(dir, false);
await this.journals.index(dirname);
journals[dirname] = 0;
}
Expand Down
Loading