mirror of
git://f0xx.org/android_cast
synced 2026-07-29 03:38:52 +03:00
AI: polish mobile parts
This commit is contained in:
15
examples/crash_reporter/backend/public/api/tag_catalog.php
Normal file
15
examples/crash_reporter/backend/public/api/tag_catalog.php
Normal file
@@ -0,0 +1,15 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
require_once __DIR__ . '/../../src/bootstrap.php';
|
||||
|
||||
if (!Auth::user()) {
|
||||
json_out(['ok' => false, 'error' => 'unauthorized'], 401);
|
||||
}
|
||||
|
||||
json_out([
|
||||
'ok' => true,
|
||||
'workflow' => TagCatalog::workflowPresets(),
|
||||
'presets' => TagCatalog::editorPresets(),
|
||||
'filter_mode_default' => 'and',
|
||||
'filter_mode_help' => 'AND = report has all listed tags; OR = any listed tag',
|
||||
]);
|
||||
59
examples/crash_reporter/backend/scripts/test_tags_api.sh
Executable file
59
examples/crash_reporter/backend/scripts/test_tags_api.sh
Executable file
@@ -0,0 +1,59 @@
|
||||
#!/usr/bin/env bash
|
||||
# Smoke-test reports list + tag edit API (session cookie after login).
|
||||
#
|
||||
# Usage:
|
||||
# export CRASH_BASE="https://f0xx.org/app/androidcast_project/crashes"
|
||||
# export CRASH_USER="admin"
|
||||
# export CRASH_PASS="secret"
|
||||
# ./scripts/test_tags_api.sh
|
||||
#
|
||||
# Or pass a browser session cookie:
|
||||
# export CRASH_COOKIE="PHPSESSID=..."
|
||||
# ./scripts/test_tags_api.sh
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
BASE="${CRASH_BASE:-http://127.0.0.1:8080}"
|
||||
COOKIE_JAR="${TMPDIR:-/tmp}/crash_api_cookies_$$.txt"
|
||||
trap 'rm -f "$COOKIE_JAR"' EXIT
|
||||
|
||||
if [[ -z "${CRASH_COOKIE:-}" ]]; then
|
||||
if [[ -z "${CRASH_USER:-}" || -z "${CRASH_PASS:-}" ]]; then
|
||||
echo "Set CRASH_USER + CRASH_PASS or CRASH_COOKIE" >&2
|
||||
exit 1
|
||||
fi
|
||||
curl -sS -c "$COOKIE_JAR" -b "$COOKIE_JAR" -X POST \
|
||||
-d "username=${CRASH_USER}&password=${CRASH_PASS}" \
|
||||
"${BASE}/login" -o /dev/null
|
||||
CURL_AUTH=(-b "$COOKIE_JAR")
|
||||
else
|
||||
CURL_AUTH=(-H "Cookie: ${CRASH_COOKIE}")
|
||||
fi
|
||||
|
||||
echo "== tag catalog =="
|
||||
curl -sS "${CURL_AUTH[@]}" "${BASE}/api/tag_catalog.php" | head -c 400
|
||||
echo ""
|
||||
|
||||
echo "== reports (first page) =="
|
||||
LIST=$(curl -sS "${CURL_AUTH[@]}" "${BASE}/api/reports.php?page=1&per_page=5")
|
||||
echo "$LIST" | head -c 500
|
||||
echo ""
|
||||
|
||||
ID=$(echo "$LIST" | sed -n 's/.*"id":\([0-9][0-9]*\).*/\1/p' | head -1)
|
||||
if [[ -z "$ID" ]]; then
|
||||
echo "No report id in list; skip tag write test"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo "== set tags on report #$ID (duplicate + fixed) =="
|
||||
BODY='{"id":'"$ID"',"tags":[{"id":"duplicate","label":"duplicate","bg":"#6d28d9"},{"id":"fixed","label":"fixed","bg":"#047857"}]}'
|
||||
curl -sS "${CURL_AUTH[@]}" -X POST -H "Content-Type: application/json" \
|
||||
-d "$BODY" "${BASE}/api/report_tags.php"
|
||||
echo ""
|
||||
|
||||
echo "== filter AND duplicate+fixed =="
|
||||
curl -sS "${CURL_AUTH[@]}" \
|
||||
"${BASE}/api/reports.php?tag=duplicate&tag=fixed&tag_mode=and&per_page=3" | head -c 400
|
||||
echo ""
|
||||
|
||||
echo "OK"
|
||||
84
examples/crash_reporter/backend/src/TagCatalog.php
Normal file
84
examples/crash_reporter/backend/src/TagCatalog.php
Normal file
@@ -0,0 +1,84 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
/** Workflow triage tags — multiple labels per report allowed (e.g. duplicate + fixed). */
|
||||
final class TagCatalog {
|
||||
/** @var list<array{id:string,label:string,bg:string}>|null */
|
||||
private static ?array $workflow = null;
|
||||
|
||||
/** @return list<array{id:string,label:string,bg:string}> */
|
||||
public static function workflowPresets(): array {
|
||||
if (self::$workflow !== null) {
|
||||
return self::$workflow;
|
||||
}
|
||||
self::$workflow = [
|
||||
['id' => 'in-progress', 'label' => 'in progress', 'bg' => '#3d8bfd'],
|
||||
['id' => 'fixed', 'label' => 'fixed', 'bg' => '#047857'],
|
||||
['id' => 'rejected', 'label' => 'rejected', 'bg' => '#dc2626'],
|
||||
['id' => 'done', 'label' => 'done', 'bg' => '#5c6b82'],
|
||||
['id' => 'not-reproducible', 'label' => 'not reproducible', 'bg' => '#d97706'],
|
||||
['id' => 'not-a-bug', 'label' => 'not a bug', 'bg' => '#6b7280'],
|
||||
['id' => 'duplicate', 'label' => 'duplicate', 'bg' => '#6d28d9'],
|
||||
];
|
||||
return self::$workflow;
|
||||
}
|
||||
|
||||
/** @return array<string, true> */
|
||||
public static function workflowIds(): array {
|
||||
$map = [];
|
||||
foreach (self::workflowPresets() as $tag) {
|
||||
$map[$tag['id']] = true;
|
||||
}
|
||||
return $map;
|
||||
}
|
||||
|
||||
public static function isWorkflowId(string $id): bool {
|
||||
return isset(self::workflowIds()[$id]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param list<string> $raw from query (?tag=fixed&tag=duplicate)
|
||||
* @return list<string>
|
||||
*/
|
||||
public static function normalizeFilterIds(array $raw): array {
|
||||
$out = [];
|
||||
$seen = [];
|
||||
foreach ($raw as $item) {
|
||||
$id = strtolower(trim((string) $item));
|
||||
$id = preg_replace('/[^a-z0-9_-]+/i', '-', $id) ?? '';
|
||||
$id = trim($id, '-');
|
||||
if ($id === '' || strlen($id) > 32 || isset($seen[$id])) {
|
||||
continue;
|
||||
}
|
||||
if (isset(array_flip(report_reserved_tag_ids())[$id])) {
|
||||
continue;
|
||||
}
|
||||
$seen[$id] = true;
|
||||
$out[] = $id;
|
||||
if (count($out) >= 8) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return $out;
|
||||
}
|
||||
|
||||
/**
|
||||
* Workflow presets first, then distinct custom tags from DB (excluding workflow ids).
|
||||
*
|
||||
* @return list<array{id:string,label:string,bg:string}>
|
||||
*/
|
||||
public static function editorPresets(int $historicalLimit = 32): array {
|
||||
$map = [];
|
||||
foreach (self::workflowPresets() as $tag) {
|
||||
$map[$tag['id']] = $tag;
|
||||
}
|
||||
foreach (ReportRepository::listTagPresets($historicalLimit + 20) as $tag) {
|
||||
$id = (string) ($tag['id'] ?? '');
|
||||
if ($id === '' || isset($map[$id])) {
|
||||
continue;
|
||||
}
|
||||
$map[$id] = $tag;
|
||||
}
|
||||
return array_values($map);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user