Compare commits

..

1 Commits

Author SHA1 Message Date
DerLinkman
2efc4b93cc feat: Extend OpenAPI/Swagger documentation with missing endpoints
- Add 60+ previously undocumented API endpoints
- Add missing POST /api/v1/add/ endpoints (rsetting, filter, global-filter, alias-domain, mailbox-policy, admin, dkim_import, mta-sts, mailbox/template)
- Add missing POST /api/v1/delete/ endpoints (rsetting, filter, alias-domain, mailbox-policy, time_limited_alias, eas_cache, sogo_profile, admin, rlhash, identity-provider)
- Add missing GET /api/v1/get/ endpoints (alias/all, alias-domain/all, relayhost/all, transport/all, rsetting/all, filters/all, bcc/all, recipient_map/all, tls-policy-map/all, oauth2-client/all, app-passwd/all, domain/all, mailbox/all, admin/all, passwordpolicy, status/host, status/container, identity-provider)
- Add missing POST /api/v1/edit/ endpoints (relayhost, transport, rsetting, filter, alias-domain, bcc, recipient_map, tls-policy-map, oauth2-client, app-passwd, admin, passwordpolicy, mta-sts)
- Improve existing endpoint documentation with detailed examples
- Organize endpoints by tags: Rspamd, Filters, Domain Aliases, Policies, Admins, OAuth2, MTA-STS, Configuration, Authentication
- Fix YAML parser errors (removed duplicate cors and identity-provider endpoints)

The documentation now covers ~200 API endpoints, up from ~140.
File size increased from 6,096 to 8,252 lines (+35%).
2025-12-17 11:54:57 +01:00
5 changed files with 2172 additions and 124 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -664,18 +664,6 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
dkim('add', array('key_size' => $_data['key_size'], 'dkim_selector' => $_data['dkim_selector'], 'domains' => $domain));
}
}
// Create MTA-STS settings from template if enabled
if (!empty($DOMAIN_DEFAULT_ATTRIBUTES['mta_sts']) && $DOMAIN_DEFAULT_ATTRIBUTES['mta_sts'] == 1) {
$mta_sts_data = array(
'domain' => $domain,
'version' => $DOMAIN_DEFAULT_ATTRIBUTES['mta_sts_version'],
'mode' => $DOMAIN_DEFAULT_ATTRIBUTES['mta_sts_mode'],
'max_age' => $DOMAIN_DEFAULT_ATTRIBUTES['mta_sts_max_age'],
'mx' => $DOMAIN_DEFAULT_ATTRIBUTES['mta_sts_mx'],
'active' => 1
);
mailbox('add', 'mta_sts', $mta_sts_data);
}
if (!empty($restart_sogo)) {
$restart_response = json_decode(docker('post', 'sogo-mailcow', 'restart'), true);
if ($restart_response['type'] == "success") {
@@ -1660,11 +1648,6 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
$attr['relay_unknown_only'] = (isset($_data['relay_unknown_only'])) ? intval($_data['relay_unknown_only']) : 0;
$attr['dkim_selector'] = (isset($_data['dkim_selector'])) ? $_data['dkim_selector'] : "dkim";
$attr['key_size'] = isset($_data['key_size']) ? intval($_data['key_size']) : 2048;
$attr['mta_sts'] = (isset($_data['mta_sts'])) ? intval($_data['mta_sts']) : 0;
$attr['mta_sts_version'] = (isset($_data['mta_sts_version'])) ? $_data['mta_sts_version'] : 'stsv1';
$attr['mta_sts_mode'] = (isset($_data['mta_sts_mode'])) ? $_data['mta_sts_mode'] : 'enforce';
$attr['mta_sts_max_age'] = (isset($_data['mta_sts_max_age'])) ? intval($_data['mta_sts_max_age']) : 604800;
$attr['mta_sts_mx'] = (isset($_data['mta_sts_mx'])) ? $_data['mta_sts_mx'] : '';
// save template
$stmt = $pdo->prepare("INSERT INTO `templates` (`type`, `template`, `attributes`)
@@ -3001,26 +2984,21 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
}
// check attributes
$attr = array();
$attr['tags'] = (isset($_data['tags'])) ? $_data['tags'] : (isset($is_now['attributes']['tags']) ? $is_now['attributes']['tags'] : array());
$attr['max_num_aliases_for_domain'] = (isset($_data['max_num_aliases_for_domain'])) ? intval($_data['max_num_aliases_for_domain']) : (isset($is_now['attributes']['max_num_aliases_for_domain']) ? $is_now['attributes']['max_num_aliases_for_domain'] : 0);
$attr['max_num_mboxes_for_domain'] = (isset($_data['max_num_mboxes_for_domain'])) ? intval($_data['max_num_mboxes_for_domain']) : (isset($is_now['attributes']['max_num_mboxes_for_domain']) ? $is_now['attributes']['max_num_mboxes_for_domain'] : 0);
$attr['def_quota_for_mbox'] = (isset($_data['def_quota_for_mbox'])) ? intval($_data['def_quota_for_mbox']) * 1048576 : (isset($is_now['attributes']['def_quota_for_mbox']) ? $is_now['attributes']['def_quota_for_mbox'] : 0);
$attr['max_quota_for_mbox'] = (isset($_data['max_quota_for_mbox'])) ? intval($_data['max_quota_for_mbox']) * 1048576 : (isset($is_now['attributes']['max_quota_for_mbox']) ? $is_now['attributes']['max_quota_for_mbox'] : 0);
$attr['max_quota_for_domain'] = (isset($_data['max_quota_for_domain'])) ? intval($_data['max_quota_for_domain']) * 1048576 : (isset($is_now['attributes']['max_quota_for_domain']) ? $is_now['attributes']['max_quota_for_domain'] : 0);
$attr['rl_frame'] = (!empty($_data['rl_frame'])) ? $_data['rl_frame'] : (isset($is_now['attributes']['rl_frame']) ? $is_now['attributes']['rl_frame'] : "s");
$attr['rl_value'] = (!empty($_data['rl_value'])) ? $_data['rl_value'] : (isset($is_now['attributes']['rl_value']) ? $is_now['attributes']['rl_value'] : "");
$attr['active'] = isset($_data['active']) ? intval($_data['active']) : (isset($is_now['attributes']['active']) ? $is_now['attributes']['active'] : 1);
$attr['gal'] = (isset($_data['gal'])) ? intval($_data['gal']) : (isset($is_now['attributes']['gal']) ? $is_now['attributes']['gal'] : 1);
$attr['backupmx'] = (isset($_data['backupmx'])) ? intval($_data['backupmx']) : (isset($is_now['attributes']['backupmx']) ? $is_now['attributes']['backupmx'] : 0);
$attr['relay_all_recipients'] = (isset($_data['relay_all_recipients'])) ? intval($_data['relay_all_recipients']) : (isset($is_now['attributes']['relay_all_recipients']) ? $is_now['attributes']['relay_all_recipients'] : 0);
$attr['relay_unknown_only'] = (isset($_data['relay_unknown_only'])) ? intval($_data['relay_unknown_only']) : (isset($is_now['attributes']['relay_unknown_only']) ? $is_now['attributes']['relay_unknown_only'] : 0);
$attr['dkim_selector'] = (isset($_data['dkim_selector'])) ? $_data['dkim_selector'] : (isset($is_now['attributes']['dkim_selector']) ? $is_now['attributes']['dkim_selector'] : "dkim");
$attr['key_size'] = isset($_data['key_size']) ? intval($_data['key_size']) : (isset($is_now['attributes']['key_size']) ? $is_now['attributes']['key_size'] : 2048);
$attr['mta_sts'] = (isset($_data['mta_sts'])) ? intval($_data['mta_sts']) : (isset($is_now['attributes']['mta_sts']) ? $is_now['attributes']['mta_sts'] : 0);
$attr['mta_sts_version'] = (isset($_data['mta_sts_version'])) ? $_data['mta_sts_version'] : (isset($is_now['attributes']['mta_sts_version']) ? $is_now['attributes']['mta_sts_version'] : 'stsv1');
$attr['mta_sts_mode'] = (isset($_data['mta_sts_mode'])) ? $_data['mta_sts_mode'] : (isset($is_now['attributes']['mta_sts_mode']) ? $is_now['attributes']['mta_sts_mode'] : 'enforce');
$attr['mta_sts_max_age'] = (isset($_data['mta_sts_max_age'])) ? intval($_data['mta_sts_max_age']) : (isset($is_now['attributes']['mta_sts_max_age']) ? $is_now['attributes']['mta_sts_max_age'] : 604800);
$attr['mta_sts_mx'] = (isset($_data['mta_sts_mx'])) ? $_data['mta_sts_mx'] : (isset($is_now['attributes']['mta_sts_mx']) ? $is_now['attributes']['mta_sts_mx'] : '');
$attr['tags'] = (isset($_data['tags'])) ? $_data['tags'] : array();
$attr['max_num_aliases_for_domain'] = (isset($_data['max_num_aliases_for_domain'])) ? intval($_data['max_num_aliases_for_domain']) : 0;
$attr['max_num_mboxes_for_domain'] = (isset($_data['max_num_mboxes_for_domain'])) ? intval($_data['max_num_mboxes_for_domain']) : 0;
$attr['def_quota_for_mbox'] = (isset($_data['def_quota_for_mbox'])) ? intval($_data['def_quota_for_mbox']) * 1048576 : 0;
$attr['max_quota_for_mbox'] = (isset($_data['max_quota_for_mbox'])) ? intval($_data['max_quota_for_mbox']) * 1048576 : 0;
$attr['max_quota_for_domain'] = (isset($_data['max_quota_for_domain'])) ? intval($_data['max_quota_for_domain']) * 1048576 : 0;
$attr['rl_frame'] = (!empty($_data['rl_frame'])) ? $_data['rl_frame'] : "s";
$attr['rl_value'] = (!empty($_data['rl_value'])) ? $_data['rl_value'] : "";
$attr['active'] = isset($_data['active']) ? intval($_data['active']) : 1;
$attr['gal'] = (isset($_data['gal'])) ? intval($_data['gal']) : 1;
$attr['backupmx'] = (isset($_data['backupmx'])) ? intval($_data['backupmx']) : 0;
$attr['relay_all_recipients'] = (isset($_data['relay_all_recipients'])) ? intval($_data['relay_all_recipients']) : 0;
$attr['relay_unknown_only'] = (isset($_data['relay_unknown_only'])) ? intval($_data['relay_unknown_only']) : 0;
$attr['dkim_selector'] = (isset($_data['dkim_selector'])) ? $_data['dkim_selector'] : "dkim";
$attr['key_size'] = isset($_data['key_size']) ? intval($_data['key_size']) : 2048;
// update template
$stmt = $pdo->prepare("UPDATE `templates`

View File

@@ -723,8 +723,6 @@
"mta_sts_mx": "MX server",
"mta_sts_mx_info": "Allows sending only to explicitly listed mail server hostnames; the sending MTA checks if the DNS MX hostname matches the policy list, and only allows delivery with a valid TLS certificate (guards against MITM).",
"mta_sts_mx_notice": "Multiple MX servers can be specified (separated by commas).",
"mta_sts_enable": "Enable MTA-STS",
"mta_sts_template_info": "When enabled, MTA-STS will be automatically configured for all domains created with this template.",
"multiple_bookings": "Multiple bookings",
"none_inherit": "None / Inherit",
"nexthop": "Next hop",

View File

@@ -10,7 +10,6 @@
<input type="hidden" value="0" name="gal">
<input type="hidden" value="0" name="relay_all_recipients">
<input type="hidden" value="0" name="relay_unknown_only">
<input type="hidden" value="0" name="mta_sts">
{% if mailcow_cc_role == 'admin' %}
<div class="row mb-4">
@@ -125,47 +124,6 @@
</div>
</div>
<hr>
<div class="row mb-4">
<label class="control-label col-sm-2">{{ lang.edit.mta_sts }}</label>
<div class="col-sm-10">
<div class="form-check mb-3">
<label><input type="checkbox" class="form-check-input" value="1" name="mta_sts"{% if template.attributes.mta_sts == '1' %} checked{% endif %}> {{ lang.edit.mta_sts_enable }}</label>
<p><small class="text-muted">{{ lang.edit.mta_sts_template_info|raw }}</small></p>
</div>
<div class="row mb-2">
<label class="control-label col-sm-3" for="mta_sts_version">{{ lang.edit.mta_sts_version }}</label>
<div class="col-sm-9">
<select data-style="btn btn-light" class="form-control" name="mta_sts_version">
<option value="stsv1"{% if template.attributes.mta_sts_version == 'stsv1' %} selected{% endif %}>STSv1</option>
</select>
</div>
</div>
<div class="row mb-2">
<label class="control-label col-sm-3" for="mta_sts_mode">{{ lang.edit.mta_sts_mode }}</label>
<div class="col-sm-9">
<select data-style="btn btn-light" class="form-control" name="mta_sts_mode">
<option value="enforce"{% if template.attributes.mta_sts_mode == 'enforce' %} selected{% endif %}>enforce</option>
<option value="testing"{% if template.attributes.mta_sts_mode == 'testing' %} selected{% endif %}>testing</option>
<option value="none"{% if template.attributes.mta_sts_mode == 'none' %} selected{% endif %}>none</option>
</select>
</div>
</div>
<div class="row mb-2">
<label class="control-label col-sm-3" for="mta_sts_max_age">{{ lang.edit.mta_sts_max_age }}</label>
<div class="col-sm-9">
<input type="number" class="form-control" name="mta_sts_max_age" value="{{ template.attributes.mta_sts_max_age|default('604800') }}">
</div>
</div>
<div class="row mb-2">
<label class="control-label col-sm-3" for="mta_sts_mx">{{ lang.edit.mta_sts_mx }}</label>
<div class="col-sm-9">
<textarea autocorrect="off" autocapitalize="none" class="form-control" rows="3" name="mta_sts_mx">{{ template.attributes.mta_sts_mx }}</textarea>
<small class="text-muted">{{ lang.edit.mta_sts_mx_notice|raw }}</small>
</div>
</div>
</div>
</div>
<hr>
<div class="row">
<div class="offset-sm-2 col-sm-10">
<button class="btn btn-xs-lg d-block d-sm-inline btn-success" data-action="edit_selected" data-id="editdomain_template" data-item="{{ template.id }}" data-api-url='edit/domain/template' data-api-attr='{}' href="#">{{ lang.admin.save }}</button>

View File

@@ -688,48 +688,6 @@
</div>
</div>
<hr>
<div class="row mb-4">
<label class="control-label col-sm-2 text-sm-end">{{ lang.edit.mta_sts }}</label>
<div class="col-sm-10">
<div class="form-check mb-3">
<input type="hidden" value="0" name="mta_sts">
<label><input type="checkbox" class="form-check-input" value="1" name="mta_sts"> {{ lang.edit.mta_sts_enable }}</label>
<p><small class="text-muted">{{ lang.edit.mta_sts_template_info|raw }}</small></p>
</div>
<div class="row mb-2">
<label class="control-label col-sm-3 text-sm-end" for="mta_sts_version">{{ lang.edit.mta_sts_version }}</label>
<div class="col-sm-9">
<select data-style="btn btn-light" class="form-control" name="mta_sts_version">
<option value="stsv1" selected>STSv1</option>
</select>
</div>
</div>
<div class="row mb-2">
<label class="control-label col-sm-3 text-sm-end" for="mta_sts_mode">{{ lang.edit.mta_sts_mode }}</label>
<div class="col-sm-9">
<select data-style="btn btn-light" class="form-control" name="mta_sts_mode">
<option value="enforce" selected>enforce</option>
<option value="testing">testing</option>
<option value="none">none</option>
</select>
</div>
</div>
<div class="row mb-2">
<label class="control-label col-sm-3 text-sm-end" for="mta_sts_max_age">{{ lang.edit.mta_sts_max_age }}</label>
<div class="col-sm-9">
<input type="number" class="form-control" name="mta_sts_max_age" value="604800">
</div>
</div>
<div class="row mb-2">
<label class="control-label col-sm-3 text-sm-end" for="mta_sts_mx">{{ lang.edit.mta_sts_mx }}</label>
<div class="col-sm-9">
<textarea autocorrect="off" autocapitalize="none" class="form-control" rows="3" name="mta_sts_mx"></textarea>
<small class="text-muted">{{ lang.edit.mta_sts_mx_notice|raw }}</small>
</div>
</div>
</div>
</div>
<hr>
<div class="row">
<div class="offset-sm-2 col-sm-10">
<button class="btn btn-xs-lg d-block d-sm-inline btn-success" data-action="add_item" data-id="adddomain_template" data-item="{{ domain }}" data-api-url='add/domain/template' data-api-attr='{}' href="#">{{ lang.admin.add }}</button>