Skip to content

Commit 80d56d7

Browse files
Update directadmin_api.py
1 parent 7a0fd52 commit 80d56d7

File tree

1 file changed

+149
-58
lines changed

1 file changed

+149
-58
lines changed

app/directadmin_api.py

Lines changed: 149 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -280,45 +280,91 @@ def get_forwarders(self):
280280
forwarders = []
281281

282282
if isinstance(response, dict):
283-
# Look for any sign of forwarders in the response
284-
for key, value in response.items():
285-
print(f"Processing key: '{key}' with value: '{value}'")
286-
287-
if key.startswith('error'):
288-
print(f"Found error: {value}")
289-
continue
290-
291-
# Various possible formats
292-
if '@' in str(key):
293-
forwarders.append({
294-
'address': key,
295-
'destination': str(value)
296-
})
297-
elif 'forward' in str(key).lower():
298-
print(f"Found forward-related key: {key} = {value}")
299-
elif value and '=' in str(value):
300-
parts = str(value).split('=', 1)
283+
# DirectAdmin commonly uses these formats for forwarders:
284+
285+
# Format 1: select0, select1, etc. (common for lists)
286+
select_keys = [k for k in response.keys() if k.startswith('select')]
287+
if select_keys:
288+
print(f"Found select keys: {select_keys}")
289+
for key in select_keys:
290+
value = response[key]
291+
if '=' in str(value):
292+
# Format: alias=destination
293+
parts = str(value).split('=', 1)
294+
if len(parts) == 2:
295+
forwarders.append({
296+
'address': f"{parts[0]}@{self.domain}",
297+
'destination': parts[1]
298+
})
299+
elif '@' in str(value):
300+
# Might be just the email address
301+
# Check if there's a corresponding destination key
302+
dest_key = key.replace('select', 'destination')
303+
if dest_key in response:
304+
forwarders.append({
305+
'address': value,
306+
'destination': response[dest_key]
307+
})
308+
309+
# Format 2: list[] array
310+
elif 'list' in response and isinstance(response['list'], list):
311+
print("Found list array")
312+
for item in response['list']:
313+
if '=' in str(item):
314+
parts = str(item).split('=', 1)
315+
if len(parts) == 2:
316+
forwarders.append({
317+
'address': f"{parts[0]}@{self.domain}" if '@' not in parts[0] else parts[0],
318+
'destination': parts[1]
319+
})
320+
321+
# Format 3: Direct email keys
322+
else:
323+
# Look for email addresses as keys
324+
for key, value in response.items():
325+
if key.startswith('error') or key == 'domain':
326+
continue
327+
328+
# If key contains @ it's likely an email
329+
if '@' in str(key):
330+
forwarders.append({
331+
'address': key,
332+
'destination': str(value)
333+
})
334+
# If key is a username and value contains destination
335+
elif value and '=' not in str(key):
336+
# Could be username as key, destination as value
337+
if '@' in str(value):
338+
forwarders.append({
339+
'address': f"{key}@{self.domain}",
340+
'destination': str(value)
341+
})
342+
# Or could be a forward entry
343+
elif '=' in str(value):
344+
parts = str(value).split('=', 1)
345+
if len(parts) == 2:
346+
forwarders.append({
347+
'address': f"{parts[0]}@{self.domain}" if '@' not in parts[0] else parts[0],
348+
'destination': parts[1]
349+
})
350+
351+
elif isinstance(response, str):
352+
print("Response is string, parsing...")
353+
lines = response.strip().split('\n')
354+
for line in lines:
355+
line = line.strip()
356+
if '=' in line:
357+
parts = line.split('=', 1)
301358
if len(parts) == 2:
302359
forwarders.append({
303-
'address': parts[0],
360+
'address': f"{parts[0]}@{self.domain}" if '@' not in parts[0] else parts[0],
304361
'destination': parts[1]
305362
})
306363

307-
elif isinstance(response, str):
308-
print("Response is string, checking for forwarders...")
309-
# Maybe it's a different format
310-
if '@' in response:
311-
lines = response.strip().split('\n')
312-
for line in lines:
313-
if '=' in line and '@' in line:
314-
parts = line.split('=', 1)
315-
if len(parts) == 2:
316-
forwarders.append({
317-
'address': parts[0].strip(),
318-
'destination': parts[1].strip()
319-
})
364+
print(f"\nParsed {len(forwarders)} forwarders:")
365+
for f in forwarders:
366+
print(f" {f['address']} -> {f['destination']}")
320367

321-
print(f"\nParsed {len(forwarders)} forwarders")
322368
return forwarders
323369

324370
except Exception as e:
@@ -330,41 +376,86 @@ def get_forwarders(self):
330376
def create_forwarder(self, address, destination):
331377
"""Create an email forwarder"""
332378
try:
333-
# Ensure full email addresses
334-
if '@' not in address:
335-
address = f"{address}@{self.domain}"
379+
# Ensure we have just the username part
380+
if '@' in address:
381+
username = address.split('@')[0]
382+
else:
383+
username = address
384+
385+
# Various parameter formats DirectAdmin might expect
386+
param_sets = [
387+
# Format 1: Standard 【1】
388+
{
389+
'domain': self.domain,
390+
'action': 'create',
391+
'user': username,
392+
'email': destination
393+
},
394+
# Format 2: With select0
395+
{
396+
'domain': self.domain,
397+
'action': 'create',
398+
'select0': username,
399+
'email': destination
400+
},
401+
# Format 3: Forward specific
402+
{
403+
'domain': self.domain,
404+
'action': 'create',
405+
'forward': f"{username}={destination}"
406+
}
407+
]
336408

337-
# Extract username from address
338-
username = address.split('@')[0]
409+
print(f"\n=== Creating Forwarder ===")
410+
print(f"Username: {username}")
411+
print(f"Domain: {self.domain}")
412+
print(f"Destination: {destination}")
339413

340-
endpoint = '/CMD_API_EMAIL_FORWARDERS'
341-
data = {
342-
'domain': self.domain,
343-
'action': 'create',
344-
'user': username,
345-
'email': destination
346-
}
414+
response = None
415+
for i, data in enumerate(param_sets):
416+
print(f"\nTrying parameter set {i+1}: {data}")
347417

348-
print(f"\n=== Creating Forwarder ===")
349-
print(f"Address: {address} -> {destination}")
418+
endpoint = '/CMD_API_EMAIL_FORWARDERS'
419+
response = self._make_request(endpoint, data, method='POST')
350420

351-
response = self._make_request(endpoint, data)
421+
if response:
422+
print(f"Got response: {response}")
423+
424+
if isinstance(response, dict):
425+
# Check for errors
426+
if 'error' in response:
427+
error_msg = response.get('error', 'Unknown error')
428+
error_code = response.get('error_code', '')
429+
details = response.get('details', '')
430+
text = response.get('text', '')
431+
432+
# API error 1 often means permission or format issues 【2】
433+
if error_msg == '1' or error_code == '1':
434+
print(f"API Error 1 detected. Details: {details}, Text: {text}")
435+
# Try next parameter set
436+
continue
437+
else:
438+
return False, f"Error: {error_msg} {details} {text}".strip()
352439

353-
if response:
354-
# Check for success
355-
if isinstance(response, dict):
356-
if 'error' in response:
357-
return False, response.get('error', 'Unknown error')
358-
elif 'success' in response or 'created' in response:
359-
return True, f"Forwarder {address}{destination} created successfully"
440+
# Check for success indicators
441+
if any(key in response for key in ['success', 'created', 'added']):
442+
return True, f"Forwarder {username}@{self.domain}{destination} created"
360443

361-
# If no error, assume success
362-
return True, f"Forwarder {address}{destination} created"
444+
# If no error and no explicit success, might still be OK
445+
if not any(key.startswith('error') for key in response.keys()):
446+
return True, f"Forwarder {username}@{self.domain}{destination} created"
363447

364-
return False, "Failed to create forwarder"
448+
elif isinstance(response, str):
449+
if 'error' not in response.lower():
450+
return True, f"Forwarder {username}@{self.domain}{destination} created"
451+
452+
# If all parameter sets failed
453+
return False, "Failed to create forwarder. Check DirectAdmin logs for details."
365454

366455
except Exception as e:
367456
print(f"Error creating forwarder: {e}")
457+
import traceback
458+
traceback.print_exc()
368459
return False, str(e)
369460

370461
def delete_forwarder(self, address):

0 commit comments

Comments
 (0)