Full update/deletion on abstract page

This commit is contained in:
nemunaire 2020-06-14 22:58:28 +02:00
parent 717123ad7f
commit 4a19149b51
9 changed files with 261 additions and 81 deletions

View File

@ -52,17 +52,17 @@ func init() {
router.PUT("/api/users/:userid/domains/:domain/zones", api.ApiHandler(userHandler(domainHandler(updateUserDomainZones))))
router.POST("/api/users/:userid/domains/:domain/zones", api.ApiHandler(userHandler(domainHandler(newUserDomainZone))))
router.GET("/api/users/:userid/domains/:domain/zones/:zoneid", api.ApiHandler(zoneHandler(getZone)))
router.PUT("/api/users/:userid/domains/:domain/zones/:zoneid", api.ApiHandler(zoneHandler(updateZone)))
router.GET("/api/users/:userid/domains/:domain/zones/:zoneid", api.ApiHandler(userHandler(zoneHandler(getZone))))
router.PUT("/api/users/:userid/domains/:domain/zones/:zoneid", api.ApiHandler(userHandler(zoneHandler(updateZone))))
router.DELETE("/api/users/:userid/domains/:domain/zones/:zoneid", api.ApiHandler(deleteZone))
router.GET("/api/zones/:zoneid", api.ApiHandler(zoneHandler(getZone)))
router.PUT("/api/zones/:zoneid", api.ApiHandler(zoneHandler(updateZone)))
router.GET("/api/zones/:zoneid", api.ApiHandler(userHandler(zoneHandler(getZone))))
router.PUT("/api/zones/:zoneid", api.ApiHandler(userHandler(zoneHandler(updateZone))))
router.DELETE("/api/zones/:zoneid", api.ApiHandler(deleteZone))
router.GET("/api/users/:userid/domains/:domain/zones/:zoneid/:serviceid", api.ApiHandler(zoneHandler(getZoneService)))
router.PUT("/api/users/:userid/domains/:domain/zones/:zoneid/:serviceid", api.ApiHandler(zoneHandler(updateZoneService)))
router.PATCH("/api/users/:userid/domains/:domain/zones/:zoneid", api.ApiHandler(zoneHandler(patchZoneService)))
router.GET("/api/users/:userid/domains/:domain/zones/:zoneid/*serviceid", api.ApiHandler(userHandler(zoneHandler(getZoneService))))
router.PUT("/api/users/:userid/domains/:domain/zones/:zoneid/*serviceid", api.ApiHandler(userHandler(zoneHandler(updateZoneService))))
router.PATCH("/api/users/:userid/domains/:domain/zones/:zoneid", api.ApiHandler(userHandler(zoneHandler(patchZoneService))))
}
func getUserDomainZones(_ *config.Options, domain *happydns.Domain, _ httprouter.Params, _ io.Reader) api.Response {
@ -89,27 +89,41 @@ func newUserDomainZone(_ *config.Options, domain *happydns.Domain, _ httprouter.
return api.NewAPIResponse(uz, storage.MainStore.CreateZone(uz))
}
func zoneHandler(f func(*config.Options, *happydns.Zone, httprouter.Params, io.Reader) api.Response) func(*config.Options, httprouter.Params, io.Reader) api.Response {
return func(opts *config.Options, ps httprouter.Params, body io.Reader) api.Response {
zoneid, err := strconv.ParseInt(ps.ByName("zoneid"), 10, 64)
if err != nil {
return api.NewAPIErrorResponse(http.StatusNotFound, err)
} else {
func zoneHandler(f func(*config.Options, *happydns.Domain, *happydns.Zone, httprouter.Params, io.Reader) api.Response) func(*config.Options, *happydns.User, httprouter.Params, io.Reader) api.Response {
return func(opts *config.Options, user *happydns.User, ps httprouter.Params, body io.Reader) api.Response {
return domainHandler(func(opts *config.Options, domain *happydns.Domain, ps httprouter.Params, body io.Reader) api.Response {
zoneid, err := strconv.ParseInt(ps.ByName("zoneid"), 10, 64)
if err != nil {
return api.NewAPIErrorResponse(http.StatusNotFound, err)
}
// Check that the zoneid exists in the domain history
found := false
for _, v := range domain.ZoneHistory {
if v.Id == zoneid {
found = true
break
}
}
if !found {
return api.NewAPIErrorResponse(http.StatusNotFound, fmt.Errorf("Zone not found"))
}
zone, err := storage.MainStore.GetZone(zoneid)
if err != nil {
return api.NewAPIErrorResponse(http.StatusNotFound, err)
} else {
return f(opts, zone, ps, body)
return f(opts, domain, zone, ps, body)
}
}
})(opts, user, ps, body)
}
}
func getZone(_ *config.Options, zone *happydns.Zone, _ httprouter.Params, _ io.Reader) api.Response {
func getZone(_ *config.Options, domain *happydns.Domain, zone *happydns.Zone, _ httprouter.Params, _ io.Reader) api.Response {
return api.NewAPIResponse(zone, nil)
}
func updateZone(_ *config.Options, zone *happydns.Zone, _ httprouter.Params, body io.Reader) api.Response {
func updateZone(_ *config.Options, domain *happydns.Domain, zone *happydns.Zone, _ httprouter.Params, body io.Reader) api.Response {
uz := &happydns.Zone{}
err := json.NewDecoder(body).Decode(&uz)
if err != nil {
@ -120,17 +134,19 @@ func updateZone(_ *config.Options, zone *happydns.Zone, _ httprouter.Params, bod
return api.NewAPIResponse(uz, storage.MainStore.UpdateZone(uz))
}
func getZoneService(_ *config.Options, zone *happydns.Zone, ps httprouter.Params, body io.Reader) api.Response {
serviceid, err := base64.StdEncoding.DecodeString(ps.ByName("serviceid"))
func getZoneService(_ *config.Options, domain *happydns.Domain, zone *happydns.Zone, ps httprouter.Params, body io.Reader) api.Response {
serviceid, err := base64.StdEncoding.DecodeString(ps.ByName("serviceid")[1:])
if err != nil {
return api.NewAPIErrorResponse(http.StatusBadRequest, err)
}
return api.NewAPIResponse(zone.FindService(serviceid), nil)
_, svc := zone.FindService(serviceid)
return api.NewAPIResponse(svc, nil)
}
func updateZoneService(_ *config.Options, zone *happydns.Zone, ps httprouter.Params, body io.Reader) api.Response {
serviceid, err := base64.StdEncoding.DecodeString(ps.ByName("serviceid"))
func updateZoneService(_ *config.Options, domain *happydns.Domain, zone *happydns.Zone, ps httprouter.Params, body io.Reader) api.Response {
serviceid, err := base64.StdEncoding.DecodeString(ps.ByName("serviceid")[1:])
if err != nil {
return api.NewAPIErrorResponse(http.StatusBadRequest, err)
}
@ -141,7 +157,7 @@ func updateZoneService(_ *config.Options, zone *happydns.Zone, ps httprouter.Par
return api.NewAPIErrorResponse(http.StatusBadRequest, fmt.Errorf("Something is wrong in received data: %w", err))
}
err = zone.EraseService(usc.Domain, serviceid, usc)
err = zone.EraseService(usc.Domain, domain.DomainName, serviceid, usc)
if err != nil {
return api.NewAPIErrorResponse(http.StatusBadRequest, err)
}
@ -149,14 +165,14 @@ func updateZoneService(_ *config.Options, zone *happydns.Zone, ps httprouter.Par
return api.NewAPIResponse(zone.Services, storage.MainStore.UpdateZone(zone))
}
func patchZoneService(_ *config.Options, zone *happydns.Zone, _ httprouter.Params, body io.Reader) api.Response {
func patchZoneService(_ *config.Options, domain *happydns.Domain, zone *happydns.Zone, _ httprouter.Params, body io.Reader) api.Response {
usc := &happydns.ServiceCombined{}
err := json.NewDecoder(body).Decode(&usc)
if err != nil {
return api.NewAPIErrorResponse(http.StatusBadRequest, fmt.Errorf("Something is wrong in received data: %w", err))
}
err = zone.EraseService(usc.Domain, usc.Id, usc)
err = zone.EraseService(usc.Domain, domain.DomainName, usc.Id, usc)
if err != nil {
return api.NewAPIErrorResponse(http.StatusBadRequest, err)
}

View File

@ -32,6 +32,7 @@
package api
import (
"encoding/base64"
"encoding/json"
"errors"
"fmt"
@ -50,11 +51,14 @@ import (
func init() {
router.GET("/api/domains/:domain/zone/:zoneid", apiAuthHandler(zoneHandler(getZone)))
router.PATCH("/api/domains/:domain/zone/:zoneid", apiAuthHandler(zoneHandler(updateZoneService)))
router.GET("/api/domains/:domain/zone/:zoneid/:subdomain", apiAuthHandler(zoneHandler(getZoneSubdomain)))
router.GET("/api/domains/:domain/zone/:zoneid/:subdomain/*serviceid", apiAuthHandler(zoneHandler(getZoneService)))
router.DELETE("/api/domains/:domain/zone/:zoneid/:subdomain/*serviceid", apiAuthHandler(zoneHandler(deleteZoneService)))
router.POST("/api/domains/:domain/import_zone", apiAuthHandler(domainHandler(importZone)))
}
func zoneHandler(f func(*config.Options, *happydns.Domain, *happydns.Zone, io.Reader) Response) func(*config.Options, *happydns.User, httprouter.Params, io.Reader) Response {
func zoneHandler(f func(*config.Options, *happydns.Domain, *happydns.Zone, httprouter.Params, io.Reader) Response) func(*config.Options, *happydns.User, httprouter.Params, io.Reader) Response {
return func(opts *config.Options, u *happydns.User, ps httprouter.Params, body io.Reader) Response {
zoneid, err := strconv.ParseInt(ps.ByName("zoneid"), 10, 64)
if err != nil {
@ -85,18 +89,40 @@ func zoneHandler(f func(*config.Options, *happydns.Domain, *happydns.Zone, io.Re
err: errors.New("Zone not found"),
}
} else {
return f(opts, domain, zone, body)
return f(opts, domain, zone, ps, body)
}
})(opts, u, ps, body)
}
}
func getZone(opts *config.Options, domain *happydns.Domain, zone *happydns.Zone, body io.Reader) Response {
func getZone(opts *config.Options, domain *happydns.Domain, zone *happydns.Zone, _ httprouter.Params, body io.Reader) Response {
return APIResponse{
response: zone,
}
}
func getZoneSubdomain(opts *config.Options, domain *happydns.Domain, zone *happydns.Zone, ps httprouter.Params, body io.Reader) Response {
return APIResponse{
response: map[string]interface{}{
"aliases": zone.Aliases[ps.ByName("subdomain")],
"services": zone.Services[ps.ByName("subdomain")],
},
}
}
func getZoneService(opts *config.Options, domain *happydns.Domain, zone *happydns.Zone, ps httprouter.Params, body io.Reader) Response {
serviceid, err := base64.StdEncoding.DecodeString(ps.ByName("serviceid")[1:])
if err != nil {
return APIErrorResponse{
err: err,
}
}
return APIResponse{
response: zone.FindSubdomainService(ps.ByName("subdomain"), serviceid),
}
}
func importZone(opts *config.Options, domain *happydns.Domain, body io.Reader) Response {
source, err := storage.MainStore.GetSource(&happydns.User{Id: domain.IdUser}, domain.IdSource)
if err != nil {
@ -150,7 +176,7 @@ func importZone(opts *config.Options, domain *happydns.Domain, body io.Reader) R
}
}
func updateZoneService(opts *config.Options, domain *happydns.Domain, zone *happydns.Zone, body io.Reader) Response {
func updateZoneService(opts *config.Options, domain *happydns.Domain, zone *happydns.Zone, _ httprouter.Params, body io.Reader) Response {
usc := &happydns.ServiceCombined{}
err := json.NewDecoder(body).Decode(&usc)
if err != nil {
@ -159,7 +185,34 @@ func updateZoneService(opts *config.Options, domain *happydns.Domain, zone *happ
}
}
err = zone.EraseService(usc.Domain, usc.Id, usc)
err = zone.EraseService(usc.Domain, domain.DomainName, usc.Id, usc)
if err != nil {
return APIErrorResponse{
err: err,
}
}
err = storage.MainStore.UpdateZone(zone)
if err != nil {
return APIErrorResponse{
err: err,
}
}
return APIResponse{
response: zone,
}
}
func deleteZoneService(opts *config.Options, domain *happydns.Domain, zone *happydns.Zone, ps httprouter.Params, body io.Reader) Response {
serviceid, err := base64.StdEncoding.DecodeString(ps.ByName("serviceid")[1:])
if err != nil {
return APIErrorResponse{
err: err,
}
}
err = zone.EraseService(ps.ByName("subdomain"), domain.DomainName, serviceid, nil)
if err != nil {
return APIErrorResponse{
err: err,

View File

@ -44,7 +44,7 @@
</b-badge>
</b-list-group-item>
<b-list-group-item v-if="showDetails">
<h-resource-value v-model="service.Service" edit-toolbar :services="services" :type="service._svctype" @saveService="saveService(service, $event)" />
<h-resource-value v-model="service.Service" edit-toolbar :services="services" :type="service._svctype" @deleteService="deleteService(service, $event)" @saveService="saveService(service, $event)" />
</b-list-group-item>
</b-list-group>
</template>
@ -96,29 +96,52 @@ export default {
},
methods: {
saveService (service, cbSuccess, cbFail) {
ZoneApi.updateZoneService(this.origin, this.zoneMeta.id, service)
deleteService (service) {
this.showDetails = false
ZoneApi.deleteZoneService(this.origin, this.zoneMeta.id, service)
.then(
(response) => {
this.$emit('updateMyServices', response.data)
if (cbSuccess != null) {
cbSuccess()
}
},
(error) => {
this.$bvToast.toast(
error.response.data.errmsg, {
title: 'An error occurs when updating the service!',
title: 'An error occurs when deleting the service!',
autoHideDelay: 5000,
variant: 'danger',
toaster: 'b-toaster-content-right'
}
)
if (cbFail != null) {
cbFail(error)
})
},
saveService (service, cbSuccess, cbFail) {
if (service.Service === undefined) {
this.deleteService(service)
} else {
ZoneApi.updateZoneService(this.origin, this.zoneMeta.id, service)
.then(
(response) => {
this.$emit('updateMyServices', response.data)
if (cbSuccess != null) {
cbSuccess()
}
},
(error) => {
this.$bvToast.toast(
error.response.data.errmsg, {
title: 'An error occurs when updating the service!',
autoHideDelay: 5000,
variant: 'danger',
toaster: 'b-toaster-content-right'
}
)
if (cbFail != null) {
cbFail(error)
}
}
}
)
)
}
},
toogleShowDetails () {

View File

@ -32,7 +32,7 @@
-->
<template>
<component :is="itemComponent" :value="value" @input="$emit('input', $event)" :edit="edit" :edit-toolbar="editToolbar" :index="index" :services="services" :specs="specs" :type="type" @saveService="$emit('saveService', $event)" />
<component :is="itemComponent" :value="value" :edit="edit" :edit-toolbar="editToolbar" :index="index" :services="services" :specs="specs" :type="type" @input="$emit('input', $event)" @deleteService="$emit('deleteService', $event)" @saveService="$emit('saveService', $event)" />
</template>
<script>
@ -100,7 +100,7 @@ export default {
methods: {
findComponent () {
if (Array.isArray(this.value)) {
if (Array.isArray(this.value) || (this.type.substr(0, 2) === '[]' && this.type !== '[]byte' && this.type !== '[]uint8')) {
this.itemComponent = HResourceValueTable
} else if (this.type.substr(0, 3) === 'map') {
this.itemComponent = HResourceValueMap

View File

@ -39,11 +39,15 @@
<h3>
<span v-if="!editKeys[key]">{{ key }}</span>
<b-input-group v-else>
<b-form-input v-model="newKeys[key]" />
<b-form-input
v-model="newKeys[key]"
:placeholder="specs.id + ' key name'"
/>
<template v-slot:append>
<b-button v-if="editKeys[key]" type="button" size="sm" variant="primary" @click="rename(key)">
<b-icon icon="check" />
Rename
<span v-if="key">Rename</span>
<span v-else>Create new {{ specs.id }} key</span>
</b-button>
</template>
</b-input-group>
@ -52,14 +56,21 @@
</b-button>
</h3>
</b-col>
<b-col sm="auto">
<b-button type="button" size="sm" variant="outline-danger" class="mx-1 float-right">
<b-col v-if="!key || !editKeys[key]" sm="auto">
<b-button type="button" size="sm" variant="outline-danger" class="mx-1" @click="deleteKey(key)">
<b-icon icon="trash" />
Delete
</b-button>
</b-col>
<b-col v-else sm="auto">
<b-button type="button" variant="outline-danger" class="mx-1" @click="cancelKeyEdit(key)">
<b-icon icon="x-circle" />
Cancel edit
</b-button>
</b-col>
</b-row>
<h-resource-value
v-if="key"
v-model="value[key]"
:services="services"
:specs="service_specs"
@ -68,7 +79,7 @@
/>
<hr>
</div>
<b-button>
<b-button @click="createKey()">
Add new {{ specs.id }}
</b-button>
</div>
@ -132,7 +143,7 @@ export default {
watch: {
type: function () {
this.key_type = this.type.substr(this.type.indexOf('[') + 1, this.type.indexOf(']') - this.type.indexOf('['))
this.key_type = this.type.substr(this.type.indexOf('[') + 1, this.type.indexOf(']') - this.type.indexOf('[') - 1)
this.main_type = this.type.substr(this.type.indexOf(']') + 1)
this.pullServiceSpecs()
}
@ -140,7 +151,7 @@ export default {
created () {
if (this.type !== undefined) {
this.key_type = this.type.substr(this.type.indexOf('[') + 1, this.type.indexOf(']') - this.type.indexOf('['))
this.key_type = this.type.substr(this.type.indexOf('[') + 1, this.type.indexOf(']') - this.type.indexOf('[') - 1)
this.main_type = this.type.substr(this.type.indexOf(']') + 1)
this.pullServiceSpecs()
}
@ -156,17 +167,42 @@ export default {
)
},
cancelKeyEdit (key) {
Vue.delete(this.editKeys, key)
},
createKey () {
var newObj = {}
if (this.main_type.substr(0, 2) === '[]') {
newObj = []
}
Vue.set(this.value, '', newObj)
this.toogleKeyEdit('', true)
},
deleteKey (key) {
Vue.delete(this.value, key)
if (Object.keys(this.value).length === 0) {
this.$emit('input', undefined)
this.$emit('saveService')
}
},
rename (key) {
if (key !== this.newKeys[key]) {
Vue.set(this.value, this.newKeys[key], this.value[key])
Vue.delete(this.value, key)
}
Vue.delete(this.editKeys, key)
this.$emit('saveService')
},
toogleKeyEdit (key) {
toogleKeyEdit (key, forceValue) {
Vue.set(this.newKeys, key, key)
Vue.set(this.editKeys, key, !this.editKeys[key])
if (forceValue == null) {
forceValue = !this.editKeys[key]
}
Vue.set(this.editKeys, key, forceValue)
}
}
}

View File

@ -52,20 +52,25 @@
:services="services"
:specs="spec"
:type="spec.type"
@saveService="$emit('saveService', $event)"
@saveService="serviceEdit=false;$emit('saveService', $event)"
/>
<b-button v-else @click="createObject(spec)">
<b-button v-else :disable="value['']" @click="createObject(spec)">
Create {{ spec.id }}
</b-button>
</b-tab>
</b-tabs>
<div v-else-if="!value">
<b-button @click="createObject(spec)">
Create {{ spec.id }}
</b-button>
</div>
<div v-else>
<div v-if="editToolbar" class="text-right mb-2">
<b-button v-if="!editChildren" type="button" size="sm" variant="outline-primary" class="mx-1" @click="toogleServiceEdit()">
<b-icon icon="pencil" />
Edit
</b-button>
<b-button v-else type="button" size="sm" variant="primary" class="mx-1" @click="$emit('saveService', editDone)">
<b-button v-else type="button" size="sm" variant="primary" class="mx-1" @click="saveObject()">
<b-icon icon="check" />
Save those modifications
</b-button>
@ -77,11 +82,12 @@
<h-resource-value
v-for="(spec, index) in service_specs.fields"
:key="index"
v-model="value[spec.id]"
:value="val[spec.id]"
:edit="editChildren"
:services="services"
:specs="spec"
:type="spec.type"
@input="val[spec.id] = $event;$emit('input', val)"
@saveService="$emit('saveService', $event)"
/>
</div>
@ -122,14 +128,15 @@ export default {
},
value: {
type: Object,
required: true
default: null
}
},
data () {
return {
serviceEdit: false,
service_specs: null
service_specs: null,
val: {}
}
},
@ -142,6 +149,9 @@ export default {
watch: {
type: function () {
this.pullServiceSpecs()
},
value: function () {
this.updateValues()
}
},
@ -149,6 +159,9 @@ export default {
if (this.type !== undefined) {
this.pullServiceSpecs()
}
if (this.value !== undefined) {
this.updateValues()
}
},
methods: {
@ -166,10 +179,6 @@ export default {
this.$emit('saveService')
},
editDone () {
this.serviceEdit = false
},
pullServiceSpecs () {
ServiceSpecsApi.getServiceSpecs(this.type)
.then(
@ -179,8 +188,23 @@ export default {
)
},
saveObject () {
var vm = this
this.$emit('saveService', function () {
vm.serviceEdit = false
})
},
toogleServiceEdit () {
this.serviceEdit = !this.serviceEdit
},
updateValues () {
if (this.value != null) {
this.val = Object.assign({}, this.value)
} else {
this.val = {}
}
}
}
}

View File

@ -86,7 +86,7 @@ export default {
},
value: {
type: Array,
required: true
default: null
}
},
@ -165,7 +165,9 @@ export default {
},
addRow () {
this.tmp_values.push({ _key: this.value.length, _edit: true })
if ((this.value == null && this.tmp_values.length <= 1) || (this.value != null && this.tmp_values.length <= this.value.length)) {
this.tmp_values.push({ _key: this.tmp_values.length, _edit: true })
}
},
cancelEdit (row) {
@ -191,11 +193,17 @@ export default {
val[sspec.id] = row.item[sspec.id]
}, this)
if (this.value[row.item._key] !== undefined) {
if (this.value !== null && this.value[row.item._key] !== undefined) {
this.value[row.item._key] = val
this.$emit('input', this.value)
} else if (this.value === null) {
this.$emit('input', [val])
} else {
this.value.push(val)
this.$emit('input', this.value)
}
} else if (this.value === null) {
this.$emit('input', [row.item.value])
} else {
this.value[row.item._key] = row.item.value
}
@ -205,13 +213,15 @@ export default {
updateValues () {
this.tmp_values = []
this.value.forEach(function (v, k) {
if (typeof v === 'object') {
this.tmp_values.push(Object.assign({ _key: k, _edit: false }, v))
} else {
this.tmp_values.push({ _key: k, _edit: false, value: v })
}
}, this)
if (this.value !== null) {
this.value.forEach(function (v, k) {
if (typeof v === 'object') {
this.tmp_values.push(Object.assign({ _key: k, _edit: false }, v))
} else {
this.tmp_values.push({ _key: k, _edit: false, value: v })
}
}, this)
}
}
}
}

View File

@ -36,6 +36,10 @@ export default {
return Api().get('/api/domains/' + encodeURIComponent(domain) + '/zone/' + encodeURIComponent(id))
},
deleteZoneService (domain, id, service) {
return Api().delete('/api/domains/' + encodeURIComponent(domain) + '/zone/' + encodeURIComponent(id) + '/' + encodeURIComponent(service._domain) + '/' + encodeURIComponent(service._id))
},
updateZoneService (domain, id, service) {
return Api().patch('/api/domains/' + encodeURIComponent(domain) + '/zone/' + encodeURIComponent(id), service)
}

View File

@ -53,23 +53,37 @@ type Zone struct {
Services map[string][]*ServiceCombined `json:"services"`
}
func (z *Zone) FindService(id []byte) *ServiceCombined {
for _, services := range z.Services {
for _, svc := range services {
if bytes.Equal(svc.Id, id) {
return svc
}
func (z *Zone) FindService(id []byte) (string, *ServiceCombined) {
for subdomain := range z.Services {
if svc := z.FindSubdomainService(subdomain, id); svc != nil {
return subdomain, svc
}
}
return "", nil
}
func (z *Zone) FindSubdomainService(domain string, id []byte) *ServiceCombined {
for _, svc := range z.Services[domain] {
if bytes.Equal(svc.Id, id) {
return svc
}
}
return nil
}
func (z *Zone) EraseService(domain string, id []byte, s *ServiceCombined) error {
if services, ok := z.Services[domain]; ok {
func (z *Zone) EraseService(subdomain string, origin string, id []byte, s *ServiceCombined) error {
if services, ok := z.Services[subdomain]; ok {
for k, svc := range services {
if bytes.Equal(svc.Id, id) {
z.Services[domain][k] = s
if s == nil {
z.Services[subdomain] = append(z.Services[subdomain][:k], z.Services[subdomain][k+1:]...)
} else {
s.Comment = s.GenComment(origin)
s.NbResources = s.GetNbResources()
z.Services[subdomain][k] = s
}
return nil
}
}