view scid/page-index.c @ 82:44713c475974

scid: fix index page
author David Demelier <markand@malikania.fr>
date Tue, 28 Feb 2023 16:21:37 +0100
parents 71cd8447e3a4
children
line wrap: on
line source

/*
 * page-index.c -- page / route
 *
 * Copyright (c) 2021-2023 David Demelier <markand@malikania.fr>
 *
 * Permission to use, copy, modify, and/or distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#include <errno.h>
#include <string.h>

#include "db.h"
#include "pageutil.h"
#include "scid.h"
#include "theme.h"
#include "util.h"

static void
set_job_status(json_t *project, json_t *job, json_t *jobresults, size_t *ns, size_t *nf)
{
	const char *status;
	json_t *iter;
	int exitcode, sigcode;
	size_t i, rs = 0, rf = 0;

	/* Compute number of failures and number of success. */
	json_array_foreach(jobresults, i, iter) {
		json_unpack(iter, "{si si}", "exitcode", &exitcode, "sigcode", &sigcode);

		if (exitcode == 0 && sigcode == 0)
			rs++;
		else
			rf++;
	}

	/*
	 * We have three possibilities:
	 *
	 * - unknown: no result performed,
	 * - success: all results were successful,
	 * - failed: at least one has failed.
	 */
	if (rs == 0 && rf == 0)
		status = "unknown";
	else if (rf > 0)
		status = "failed";
	else
		status = "success";

	/* Append to the total. */
	*ns += rs;
	*nf += rf;

	json_object_set_new(job, "status", json_string(status));
}

static void
set_project_jobs(json_t *project, json_t *jobs)
{
	json_t *iter, *jobresults, *list;
	json_int_t job_id;
	size_t i, ns = 0, nf = 0;

	/*
	 * This is the actual list of jobs that we will put into the list card
	 * because the jobs argument may be greater than the limit.
	 */
	list = json_array();

	json_array_foreach(jobs, i, iter) {
		/* Don't populate too much. */
		if (i + 1 >= 10)
			break;

		/*
		 * For this job, find all jobresult to check how many have
		 * failed or not.
		 *
		 * Also, since we have the project name, we can remove it.
		 */
		json_object_del(iter, "project_name");
		json_unpack(iter, "{sI}", "id", &job_id);

		if (!(jobresults = db_jobresult_list_by_job_group(job_id)))
			continue;

		set_job_status(project, iter, jobresults, &ns, &nf);
		json_decref(jobresults);
		json_array_append(list, iter);
	}

	json_object_set_new(project, "jobs", list);
	json_object_set_new(project, "n-failed", json_integer(nf));
	json_object_set_new(project, "n-success", json_integer(ns));
	json_decref(jobs);
}

/*
 * For every projects, find their jobs and add them as 'jobs' property.
 */
static void
update_projects(json_t *projects)
{
	json_t *jobs, *iter;
	const char *name;
	size_t i;

	json_array_foreach(projects, i, iter) {
		/* Script is not necessary at this point. */
		json_object_del(iter, "script");
		json_unpack(iter, "{ss}", "name", &name);

		/* Find jobs for this project. */
		if (!(jobs = db_job_list(name)))
			continue;

		set_project_jobs(iter, jobs);
	}
}

static void
get(struct kreq *req)
{
	json_t *projects;
	char *data;

	/* First, fetch all projects. */
	if ((projects = db_project_list())) {
		update_projects(projects);
		data = theme_render("onPageIndex", util_json_pack("{so}",
			"projects", projects
		));
		pageutil_render(req, KHTTP_200, KMIME_TEXT_HTML, data);
		free(data);
	} else
		pageutil_status(req, KHTTP_500);
}

void
page_index(struct kreq *r)
{
	(void)r;

	switch (r->method) {
	case KMETHOD_GET:
		get(r);
		break;
	default:
		pageutil_status(r, KHTTP_400);
		break;
	}
}