hydro 套件開發隨筆記 – 1

參考自https://hydro.js.org/
該文檔未更新之內容則從https://github.com/hydro-dev/Hydro
如果不知道怎麼寫可以參考別人寫的像上面的官方的套件

Service

範例取自自己的套件hydrooj-turnstile
最基礎的

export default class TurnstileService extends Service {
    static Config = Schema.object({
        key: Schema.string().description('Turnstile key').required(),
        secret: Schema.string().description('Turnstile Secret').role('secret').required(),
    });

    constructor(ctx: Context, config: ReturnType<typeof TurnstileService.Config>) {
        super(ctx, 'hydrooj-turnstile');
    }
}    

這可以在配置管理(即/manage/config)中新增可以填數值的欄位
alt text
大概像這樣

ctx.on

// (放在constructor裡)
ctx.on('handler/after/UserRegister', async (thisArg) => {
    /* some function */
});

handler/after/UserRegister發生會叫他
IDE可以判別有什麼是可以呼叫的
(包括但不限於api/update problem/add)

ctx.Route

ctx.Route('hitokoto', '/hitokoto', hitokotoHandler);

製造一個/hitokoto的路徑,由hitokotoHandler處理
hitokoto會是那個頁面的data-page(參考注入HTML element)

Handler

class hitokotoHandler extends Handler {
    
    async get() {
    }
    async post() {
    }
}

get會在用戶提出請求時被調用(你可以給用戶渲染HTML)
post會在提交時被調用(你可以查看他給你什麼並渲染HTML)

get

async get() {
    this.response.body = ['hello', 'world'];
}

這個就不會渲染HTML 而是直接回傳資料給用戶

this.response.body = this.request.body ||{
            packages: packages,
            lockedPackages: lockedPackages,
            success: null,
            result: null
        };
this.response.template = 'manage_addons.html';
this.renderHTML(this.response.template, {title: 'manage_addons'});

這個就會渲染HTML 並且用manage_addons.html這個template去渲染
manage_addons.html會收到this.response.body內的內容
詳細可參考template 渲染

post

async post() {
}

他會收到用戶給的資訊 在this.request.body

{
    package_name : "something"
}

之類的
可以this.request.body['package_name']

怎麼讓用戶回傳可以參考template 渲染

UserFacingError

import

import { UserFacingError } from 'hydrooj';
throw new UserFacingError('Turnstile token is missing');

範例圖

注入HTML element

在你的套件建立frontend/<不能有除_以外的特殊符號>.page.tsx(放在frontend底下)

import { addPage, NamedPage } from '@hydrooj/ui-default';
addPage(new NamedPage(['hitokoto'], () => {
  console.log('我會在data-page為hitokoto的地方執行');
}));

查詢該頁 data-page

打開該網頁
右鍵 選檢查

你就會看到data-page標籤了

template 渲染

{% extends "layout/basic.html" %}
{% block content %}
<div>
    <a>這樣外面就會套用"layout/basic.html"(如下)</a>
    <a>可以參考原版的模板去extends(記得注意他是把block插到哪裡 要取相同的block名稱)</a>
</div>
{% endblock %}

alt text
可以調用剛剛講的傳入的東西

<input type="text" name="package_name" value="{{ package }}" hidden >

這樣他的value就會是body["package"]

{% for package in packages %}
<div>
    
</div>
{% endfor %}

會遍歷body["packages"]

{% if package not in lockedPackages %}
<a></a>
{% endif %}

同理

<script>
    const message = {{ result | dump | safe }};
    alert('✓ success:  ' + message);
</script>

會傳入{{ result }}

提交表單

<form method="post" class="activate-package-form">
    <div class="activate-package-item">
        <a>{{ package }}</a>
        <input type="text" name="package_name" value="{{ package }}" hidden >
        {% if package not in lockedPackages %}
        
        {% endif %}
        <button type="submit" name="action" value="update" class="btn btn--secondary">{{ _('update') }}</button>
    </div>
</form>

按下按鈕 會傳入

{
    package_name: "<{{ package }}>的值",
    action: "delete", //或"update"
}

參考

hydro-github
hydrooj-doc
和我的自製套件
hydrooj-addons-manager
hydrooj-hitokoto-google-sheet
hydrooj-turnstile