1.1.2Updated a month ago
import { Zip } from "./zip.ts";
import { Permission } from "./permissions.ts";
import type { VP_Request } from "./vp_request.ts";
import { IsSameVersionNumber, LatestVersionNumber, SerializeVersionNumber } from "../utils/version_helpers.ts";
import { Fail } from "./pak_responses/fail.ts";
import { Package, ValidateNamespacedString } from "../classes/package.ts";
import { existsSync } from "jsr:@std/fs/exists";
import { join } from "$std/path/mod.ts";
import { Sort } from "../utils/sort_utils.ts";
import { User } from "$classes/user.ts";
import { Token } from "$classes/token.ts";

export const HandlePublish = async (request: VP_Request) => {
  console.log("PUBLISH");
  if(!request.permissions.can(Permission.UPDATE_PACKAGES)) return 403;
  if(!request.body) return 400;
  if(!request.token) return 401;

  console.log("  -", request.token);

  const user = await User.findOne({
    $relationship: {
      via: Token,
      match: { uuid: request.token },
      select: 'user_id'
    }
  });

  console.log("  -", user?.username || "NO USER");

  if(!user) return 401;

  const location = request.pathname.replace('/publish', '').replace(/^\/+/, '');

  console.log("  -", ValidateNamespacedString(location) ? "valid namespace" : "NAMESPACE IS INVALID");

  if(!ValidateNamespacedString(location)) return 400;
  const {package: { version }} = Package.BreakLocation(location)!;
  if(!version) return 400;

  let _package: Package;
  
  const find_result = await Package.FindByPath(location);

  console.log("  -", find_result ? find_result.url : 'NO PACKAGE FOUND');

  const tags = JSON.parse(request.headers.get('X-Tags') || '[]') as string[];

  if(find_result) {
    _package = find_result;
    _package.versions.current = version;
    _package.tags = tags;
  } else {
    const { namespace, package: { name } } = Package.BreakLocation(location)!;

    _package = new Package({
      namespace,
      name,
      deprecated: false,
      tags,
      events: [
        {
          event: "create",
          timestamp: Date.now(),
          token: request.token,
          version
        },
        {
          event: `publish @${version}`,
          timestamp: Date.now() + 10,
          token: request.token,
          version
        },
      ],
      versions: {
        all: [version],
        latest: version,
        current: null
      },
    });

    try {
      await Zip.Unzip(request.body, join(_package.root_path, version));
    } catch(_) {
      console.log("  -", "COULD NOT UNZIP");

      return 400;
    }

    await _package.save();

    console.log("  -", "Should be OK");

    return 200;
  }

  const FORCE = request.headers.has('X-Force');
  let force_required = false;

  const version_exists = _package?.versions.all.map(SerializeVersionNumber).includes(SerializeVersionNumber(_package.versions.current!));

  if(version_exists ||
    (
      _package.versions.latest &&
      LatestVersionNumber([_package.versions.latest!, version]) == _package.versions.latest!
    )
  ) force_required = true;

  if(force_required && !request.permissions.can(Permission.OVERWRITE_PACKAGES)) return 403;

  if(version_exists && !FORCE) {
    if(IsSameVersionNumber(_package.versions.latest, version)) return Fail(`Version [${version}] already exists. Please update your version number, or use --force if you have the right permissions.`, 400);
  }

  if(_package.versions.latest && !FORCE) {
    if(LatestVersionNumber([_package.versions.latest, version]) == _package.versions.latest) return Fail(`Version [${_package.versions.latest}] is newer than the provided version [${version}]. Please update your version number, or use --force if you have the right permissions.`, 400);
  }

  if(existsSync(_package.path!)) {
    Deno.removeSync(_package.path!, {
      recursive: true
    })
  }

  try {
    await Zip.Unzip(request.body, _package.path!);
  } catch(_) {
    return 400;
  }

  if(!version_exists) {
    _package.versions.all.push(version);
  }

  if(!_package.versions.latest || [version, _package.versions.latest].sort(Sort.Version.Descending)[0] == version) {
    _package.versions.latest = version;
  }

  if(version_exists && FORCE) {
    _package.addEvent(request.token, `overwrite @${version}`);
  } else {
    _package.addEvent(request.token, `publish @${version}`);
  }

  if(_package.namespace == '@viapak' && _package.name == 'viapak') {
    console.log(`VIAPAK UPGRADE DETECTED. SELF DESTRUCT INITIATED!`);

    setTimeout(() => {
      Deno.exit(0);
    }, 5);
  }

  return 200;
}