Skip to content

Commit 4dba09a

Browse files
committed
feat(contact): add contact update implementation and validation
1 parent ede3ffc commit 4dba09a

5 files changed

Lines changed: 260 additions & 44 deletions

File tree

command/create/contact.go

Lines changed: 33 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package create
33
import (
44
"encoding/xml"
55
"errors"
6+
"strings"
67

78
"github.com/pixel365/goepp/command"
89
)
@@ -141,30 +142,44 @@ func (c *Contact) Validate() error {
141142
return nil
142143
}
143144

144-
func (c *Contact) validatePostInfo() error {
145-
for i := range c.PostalInfo {
146-
if c.PostalInfo[i].Type != Loc && c.PostalInfo[i].Type != Int {
147-
return errors.New("contact:postalInfo type must be loc or int")
148-
}
145+
func (p *PostalInfo) Validate() error {
146+
if p.Type != Loc && p.Type != Int {
147+
return errors.New("contact:postalInfo type must be loc or int")
148+
}
149149

150-
if c.PostalInfo[i].Name == "" {
151-
return errors.New("contact:postalInfo/contact:name is required")
152-
}
150+
if strings.TrimSpace(p.Name) == "" {
151+
return errors.New("contact:postalInfo/contact:name is required")
152+
}
153153

154-
if c.PostalInfo[i].Addr.City == "" {
155-
return errors.New("contact:postalInfo/contact:addr/contact:city is required")
156-
}
154+
if strings.TrimSpace(p.Addr.City) == "" {
155+
return errors.New("contact:postalInfo/contact:addr/contact:city is required")
156+
}
157157

158-
if c.PostalInfo[i].Addr.Cc == "" {
159-
return errors.New("contact:postalInfo/contact:addr/contact:cc is required")
160-
}
158+
if strings.TrimSpace(p.Addr.Cc) == "" {
159+
return errors.New("contact:postalInfo/contact:addr/contact:cc is required")
160+
}
161161

162-
if len(c.PostalInfo[i].Addr.Cc) != 2 {
163-
return errors.New("contact:postalInfo/contact:addr/contact:cc must be 2 chars")
162+
if len(p.Addr.Cc) != 2 {
163+
return errors.New("contact:postalInfo/contact:addr/contact:cc must be 2 chars")
164+
}
165+
166+
if len(p.Addr.Street) > 3 {
167+
return errors.New("contact:postalInfo/contact:addr/contact:street max is 3")
168+
}
169+
170+
for _, s := range p.Addr.Street {
171+
if strings.TrimSpace(s) == "" {
172+
return errors.New("contact:postalInfo/contact:addr/contact:street is empty")
164173
}
174+
}
165175

166-
if len(c.PostalInfo[i].Addr.Street) > 3 {
167-
return errors.New("contact:postalInfo/contact:addr/contact:street max is 3")
176+
return nil
177+
}
178+
179+
func (c *Contact) validatePostInfo() error {
180+
for i := range c.PostalInfo {
181+
if err := c.PostalInfo[i].Validate(); err != nil {
182+
return err
168183
}
169184
}
170185

command/update/contact.go

Lines changed: 182 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,182 @@
1+
package update
2+
3+
import (
4+
"errors"
5+
"strings"
6+
7+
"github.com/pixel365/goepp/command"
8+
"github.com/pixel365/goepp/command/create"
9+
)
10+
11+
type ContactData struct {
12+
Add *ContactAdd `xml:"add,omitempty"`
13+
Remove *ContactRemove `xml:"rem,omitempty"`
14+
Change *ContactChange `xml:"chg,omitempty"`
15+
command.ContactRef
16+
}
17+
18+
type ContactAdd struct {
19+
Statuses []ContactStatus `xml:"status,omitempty"`
20+
}
21+
22+
type ContactRemove struct {
23+
Statuses []ContactStatus `xml:"status,omitempty"`
24+
}
25+
26+
type ContactChange struct {
27+
Voice *string `xml:"voice,omitempty"`
28+
Fax *string `xml:"fax,omitempty"`
29+
Email *string `xml:"email,omitempty"`
30+
AuthInfo *command.AuthInfo `xml:"authInfo,omitempty"`
31+
Disclosure *Disclosure `xml:"disclose,omitempty"`
32+
PostalInfo []create.PostalInfo `xml:"postalInfo,omitempty"`
33+
}
34+
35+
type ContactStatus struct {
36+
Value string `xml:"s,attr"`
37+
}
38+
39+
type Disclosure struct {
40+
Fields []DisclosureElement `xml:",any,omitempty"`
41+
Flag bool `xml:"flag,attr"`
42+
}
43+
44+
type DisclosureElement struct {
45+
XMLName struct{} `xml:"-"`
46+
Type string `xml:"type,attr,omitempty"`
47+
Value string `xml:",chardata"`
48+
}
49+
50+
// Validate https://datatracker.ietf.org/doc/html/rfc5733#section-3.2.5
51+
func (c *ContactData) Validate() error {
52+
if c.ID == "" {
53+
return errors.New("contact:id is required")
54+
}
55+
56+
if c.Add == nil && c.Remove == nil && c.Change == nil {
57+
return errors.New("contact:add, rem or chg is required")
58+
}
59+
60+
if c.Add != nil {
61+
if err := c.Add.Validate(); err != nil {
62+
return err
63+
}
64+
}
65+
66+
if c.Remove != nil {
67+
if err := c.Remove.Validate(); err != nil {
68+
return err
69+
}
70+
}
71+
72+
if c.Change != nil {
73+
if err := c.Change.Validate(); err != nil {
74+
return err
75+
}
76+
}
77+
78+
return nil
79+
}
80+
81+
func (a *ContactAdd) Validate() error {
82+
if len(a.Statuses) == 0 {
83+
return errors.New("add:status is required")
84+
}
85+
86+
for _, s := range a.Statuses {
87+
if err := s.Validate(); err != nil {
88+
return err
89+
}
90+
}
91+
92+
return nil
93+
}
94+
95+
func (r *ContactRemove) Validate() error {
96+
if len(r.Statuses) == 0 {
97+
return errors.New("rem:status is required")
98+
}
99+
100+
for _, s := range r.Statuses {
101+
if err := s.Validate(); err != nil {
102+
return err
103+
}
104+
}
105+
106+
return nil
107+
}
108+
109+
func (c *ContactChange) Validate() error {
110+
if err := c.validateNotEmpty(); err != nil {
111+
return err
112+
}
113+
114+
if err := c.validatePostalInfo(); err != nil {
115+
return err
116+
}
117+
118+
if c.Voice != nil && strings.TrimSpace(*c.Voice) == "" {
119+
return errors.New("chg:voice is empty")
120+
}
121+
122+
if c.Fax != nil && strings.TrimSpace(*c.Fax) == "" {
123+
return errors.New("chg:fax is empty")
124+
}
125+
126+
if c.Email != nil && strings.TrimSpace(*c.Email) == "" {
127+
return errors.New("chg:email is empty")
128+
}
129+
130+
if c.AuthInfo != nil {
131+
if err := c.AuthInfo.Validate(); err != nil {
132+
return err
133+
}
134+
}
135+
136+
if c.Disclosure != nil {
137+
if err := c.Disclosure.Validate(); err != nil {
138+
return err
139+
}
140+
}
141+
142+
return nil
143+
}
144+
145+
func (c *ContactChange) validateNotEmpty() error {
146+
if len(c.PostalInfo) == 0 &&
147+
c.Voice == nil &&
148+
c.Fax == nil &&
149+
c.Email == nil &&
150+
c.AuthInfo == nil &&
151+
c.Disclosure == nil {
152+
return errors.New("chg:postalInfo, voice, fax, email, authInfo or disclose is required")
153+
}
154+
155+
return nil
156+
}
157+
158+
func (c *ContactChange) validatePostalInfo() error {
159+
for i := range c.PostalInfo {
160+
if err := c.PostalInfo[i].Validate(); err != nil {
161+
return err
162+
}
163+
}
164+
165+
return nil
166+
}
167+
168+
func (s ContactStatus) Validate() error {
169+
if strings.TrimSpace(s.Value) == "" {
170+
return errors.New("status value is required")
171+
}
172+
173+
return nil
174+
}
175+
176+
func (d *Disclosure) Validate() error {
177+
if len(d.Fields) == 0 {
178+
return errors.New("disclose:name, org, addr, voice, fax or email is required")
179+
}
180+
181+
return nil
182+
}
Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -8,26 +8,26 @@ import (
88
"github.com/pixel365/goepp/command"
99
)
1010

11-
type Domain struct {
12-
Add *Add `xml:"add,omitempty"`
13-
Remove *Remove `xml:"rem,omitempty"`
14-
Change *Change `xml:"chg,omitempty"`
11+
type DomainData struct {
12+
Add *DomainAdd `xml:"add,omitempty"`
13+
Remove *DomainRemove `xml:"rem,omitempty"`
14+
Change *DomainChange `xml:"chg,omitempty"`
1515
command.DomainRef
1616
}
1717

18-
type Add struct {
19-
NS *NS `xml:"ns,omitempty"`
20-
Contacts []Contact `xml:"contact,omitempty"`
21-
Statuses []Status `xml:"status,omitempty"`
18+
type DomainAdd struct {
19+
NS *NS `xml:"ns,omitempty"`
20+
Contacts []DomainContact `xml:"contact,omitempty"`
21+
Statuses []DomainStatus `xml:"status,omitempty"`
2222
}
2323

24-
type Remove struct {
25-
NS *NS `xml:"ns,omitempty"`
26-
Contacts []Contact `xml:"contact,omitempty"`
27-
Statuses []Status `xml:"status,omitempty"`
24+
type DomainRemove struct {
25+
NS *NS `xml:"ns,omitempty"`
26+
Contacts []DomainContact `xml:"contact,omitempty"`
27+
Statuses []DomainStatus `xml:"status,omitempty"`
2828
}
2929

30-
type Change struct {
30+
type DomainChange struct {
3131
Registrant *string `xml:"registrant,omitempty"`
3232
AuthInfo *command.AuthInfo `xml:"authInfo,omitempty"`
3333
}
@@ -40,17 +40,17 @@ type HostObject struct {
4040
Name string `xml:",chardata"`
4141
}
4242

43-
type Contact struct {
43+
type DomainContact struct {
4444
ID string `xml:",chardata"`
4545
Type string `xml:"type,attr"`
4646
}
4747

48-
type Status struct {
48+
type DomainStatus struct {
4949
Value string `xml:"s,attr"`
5050
}
5151

5252
// Validate https://datatracker.ietf.org/doc/html/rfc5731#section-3.2.5
53-
func (d *Domain) Validate() error {
53+
func (d *DomainData) Validate() error {
5454
if d.Name == "" {
5555
return errors.New("domain:name is required")
5656
}
@@ -83,7 +83,7 @@ func (d *Domain) Validate() error {
8383
return nil
8484
}
8585

86-
func (a *Add) Validate() error {
86+
func (a *DomainAdd) Validate() error {
8787
if a.NS == nil && len(a.Contacts) == 0 && len(a.Statuses) == 0 {
8888
return errors.New("add:ns, contact or status is required")
8989
}
@@ -113,7 +113,7 @@ func (a *Add) Validate() error {
113113
return nil
114114
}
115115

116-
func (r *Remove) Validate() error {
116+
func (r *DomainRemove) Validate() error {
117117
if r.NS == nil && len(r.Contacts) == 0 && len(r.Statuses) == 0 {
118118
return errors.New("rem:ns, contact or status is required")
119119
}
@@ -143,7 +143,7 @@ func (r *Remove) Validate() error {
143143
return nil
144144
}
145145

146-
func (c *Change) Validate() error {
146+
func (c *DomainChange) Validate() error {
147147
if c.Registrant == nil && c.AuthInfo == nil {
148148
return errors.New("change:registrant or/and authInfo is required")
149149
}

command/update/unmarshal.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ func (u *Update) handleToken(
4848
return errors.New("unsupported <update> object namespace: " + t.Name.Space)
4949
}
5050

51-
var x Domain
51+
var x DomainData
5252
if err := d.DecodeElement(&x, &t); err != nil {
5353
return err
5454
}

command/update/update.go

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@ import (
77
)
88

99
type Update struct {
10-
Domain *Domain
10+
Domain *DomainData
11+
Contact *ContactData
1112
}
1213

1314
func (u *Update) Name() command.CommandName {
@@ -19,13 +20,31 @@ func (u *Update) NeedAuth() bool {
1920
}
2021

2122
func (u *Update) Validate() error {
22-
if u.Domain == nil {
23-
return errors.New("exactly one update object must be present")
23+
var notNil uint8
24+
25+
if u.Domain != nil {
26+
notNil++
27+
}
28+
29+
if u.Contact != nil {
30+
notNil++
31+
}
32+
33+
if notNil != 1 {
34+
return errors.New("exactly one update command must be present")
35+
}
36+
37+
return u.validate()
38+
}
39+
40+
func (u *Update) validate() error {
41+
if u.Domain != nil {
42+
return u.Domain.Validate()
2443
}
2544

26-
if u.Domain.Add == nil && u.Domain.Remove == nil && u.Domain.Change == nil {
27-
return errors.New("at least one update object must be present")
45+
if u.Contact != nil {
46+
return u.Contact.Validate()
2847
}
2948

30-
return u.Domain.Validate()
49+
return nil
3150
}

0 commit comments

Comments
 (0)