206 lines
5.8 KiB
Zig
206 lines
5.8 KiB
Zig
const std = @import("std");
|
|
const util = @import("util");
|
|
const pkg = @import("../lib.zig");
|
|
const services = @import("../services.zig");
|
|
|
|
const Uuid = util.Uuid;
|
|
const DateTime = util.DateTime;
|
|
const ApiContext = pkg.ApiContext;
|
|
const DriveEntry = pkg.drive.DriveEntry;
|
|
|
|
pub fn upload(
|
|
alloc: std.mem.Allocator,
|
|
ctx: ApiContext,
|
|
svcs: anytype,
|
|
args: pkg.drive.UploadArgs,
|
|
body: []const u8,
|
|
) !Uuid {
|
|
const owner = ctx.userId() orelse return error.NoToken;
|
|
const file_id = try svcs.createFile(alloc, owner, .{
|
|
.filename = args.filename,
|
|
.description = args.description,
|
|
.content_type = args.content_type,
|
|
.sensitive = args.sensitive,
|
|
}, body);
|
|
|
|
const entry_id = entry: {
|
|
errdefer svcs.deleteFile(alloc, file_id) catch |err| {
|
|
std.log.err("Unable to delete file {}: {}", .{ file_id, err });
|
|
};
|
|
|
|
break :entry svcs.createDriveEntry(
|
|
alloc,
|
|
owner,
|
|
args.dir,
|
|
args.filename,
|
|
file_id,
|
|
) catch |err| switch (err) {
|
|
error.PathAlreadyExists => {
|
|
var buf: [256]u8 = undefined;
|
|
var split = std.mem.splitBackwards(u8, args.filename, ".");
|
|
const ext = split.first();
|
|
const name = split.rest();
|
|
const new_name = try std.fmt.bufPrint(&buf, "{s}.{s}.{s}", .{ name, file_id, ext });
|
|
|
|
break :entry try svcs.createDriveEntry(
|
|
alloc,
|
|
owner,
|
|
args.dir,
|
|
new_name,
|
|
file_id,
|
|
);
|
|
},
|
|
else => |e| return e,
|
|
};
|
|
};
|
|
|
|
return entry_id;
|
|
}
|
|
|
|
pub fn mkdir(
|
|
alloc: std.mem.Allocator,
|
|
ctx: ApiContext,
|
|
svcs: anytype,
|
|
parent_path: []const u8,
|
|
name: []const u8,
|
|
) !Uuid {
|
|
const user_id = ctx.userId() orelse return error.NoToken;
|
|
return try svcs.createDriveEntry(alloc, user_id, parent_path, name, null);
|
|
}
|
|
|
|
pub fn delete(
|
|
alloc: std.mem.Allocator,
|
|
ctx: ApiContext,
|
|
svcs: anytype,
|
|
path: []const u8,
|
|
) !void {
|
|
const user_id = ctx.userId() orelse return error.NoToken;
|
|
const entry = try svcs.statDriveEntry(alloc, user_id, path);
|
|
defer util.deepFree(alloc, entry);
|
|
try svcs.deleteDriveEntry(alloc, entry.id);
|
|
if (entry.file_id) |file_id| try svcs.deleteFile(alloc, file_id);
|
|
}
|
|
|
|
pub fn move(
|
|
alloc: std.mem.Allocator,
|
|
ctx: ApiContext,
|
|
svcs: anytype,
|
|
src: []const u8,
|
|
dest: []const u8,
|
|
) !void {
|
|
const user_id = ctx.userId() orelse return error.NoToken;
|
|
try svcs.moveDriveEntry(alloc, user_id, src, dest);
|
|
}
|
|
|
|
pub fn get(
|
|
alloc: std.mem.Allocator,
|
|
ctx: ApiContext,
|
|
svcs: anytype,
|
|
path: []const u8,
|
|
) !pkg.drive.DriveEntry {
|
|
const user_id = ctx.userId() orelse return error.NoToken;
|
|
const entry = try svcs.statDriveEntry(alloc, user_id, path);
|
|
defer util.deepFree(alloc, entry);
|
|
|
|
return try convert(alloc, svcs, entry, true);
|
|
}
|
|
|
|
pub fn getById(
|
|
alloc: std.mem.Allocator,
|
|
ctx: ApiContext,
|
|
svcs: anytype,
|
|
id: Uuid,
|
|
) !pkg.drive.DriveEntry {
|
|
const user_id = ctx.userId() orelse return error.NoToken;
|
|
const entry = try svcs.getDriveEntry(alloc, id);
|
|
defer util.deepFree(alloc, entry);
|
|
if (!Uuid.eql(entry.owner_id, user_id)) return error.NotFound;
|
|
|
|
return try convert(alloc, svcs, entry, true);
|
|
}
|
|
|
|
// TODO: These next two functions are more about files than drive entries, consider refactor?
|
|
|
|
pub fn update(
|
|
alloc: std.mem.Allocator,
|
|
ctx: ApiContext,
|
|
svcs: anytype,
|
|
path: []const u8,
|
|
meta: pkg.files.UpdateArgs,
|
|
) !void {
|
|
const user_id = ctx.userId() orelse return error.NoToken;
|
|
|
|
const entry = try svcs.statDriveEntry(alloc, user_id, path);
|
|
defer util.deepFree(alloc, entry);
|
|
|
|
try svcs.updateFileMetadata(alloc, entry.file_id orelse return error.NotAFile, meta);
|
|
}
|
|
|
|
pub fn dereference(
|
|
alloc: std.mem.Allocator,
|
|
_: ApiContext,
|
|
svcs: anytype,
|
|
file_id: Uuid,
|
|
) !pkg.files.DerefResult {
|
|
const meta = try svcs.statFile(alloc, file_id);
|
|
errdefer util.deepFree(alloc, meta);
|
|
|
|
return .{
|
|
.meta = meta,
|
|
.data = try svcs.derefFile(alloc, file_id),
|
|
};
|
|
}
|
|
|
|
fn convert(
|
|
alloc: std.mem.Allocator,
|
|
svcs: anytype,
|
|
entry: services.drive.DriveEntry,
|
|
recurse: bool,
|
|
) !DriveEntry {
|
|
if (entry.file_id) |file_id| return .{
|
|
.file = .{
|
|
.id = entry.id,
|
|
.owner_id = entry.owner_id,
|
|
.name = entry.name,
|
|
.path = entry.path,
|
|
.parent_directory_id = entry.parent_directory_id,
|
|
|
|
.meta = try svcs.statFile(alloc, file_id),
|
|
},
|
|
} else return .{
|
|
.dir = .{
|
|
.id = entry.id,
|
|
.owner_id = entry.owner_id,
|
|
.name = entry.name,
|
|
.path = entry.path,
|
|
.parent_directory_id = entry.parent_directory_id,
|
|
|
|
.children = blk: {
|
|
if (!recurse) break :blk null;
|
|
|
|
const children = try svcs.listDriveEntry(alloc, entry.id);
|
|
|
|
const result = alloc.alloc(DriveEntry, children.len) catch |err| {
|
|
util.deepFree(alloc, children);
|
|
return err;
|
|
};
|
|
var count: usize = 0;
|
|
errdefer for (children) |child, i| {
|
|
if (i < count)
|
|
util.deepFree(alloc, result[i])
|
|
else
|
|
util.deepFree(alloc, child);
|
|
};
|
|
defer alloc.free(children);
|
|
errdefer alloc.free(result);
|
|
|
|
for (children) |child, i| {
|
|
result[i] = try convert(alloc, svcs, child, false);
|
|
count += 1;
|
|
}
|
|
|
|
break :blk result;
|
|
},
|
|
},
|
|
};
|
|
}
|