websitepanel/WebsitePanel/Sources/WebsitePanel.EnterpriseServer.Code/Ecommerce/Provisioning/DomainNameController.cs
2013-04-30 10:47:34 +03:00

543 lines
No EOL
17 KiB
C#

// Copyright (c) 2012, Outercurve Foundation.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// - Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// - Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// - Neither the name of the Outercurve Foundation nor the names of its
// contributors may be used to endorse or promote products derived from this
// software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
// ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
using System;
using System.Data;
using System.Collections;
using System.Collections.Generic;
using WebsitePanel.EnterpriseServer;
namespace WebsitePanel.Ecommerce.EnterpriseServer
{
public class DomainNameController : ServiceProvisioningBase, IServiceProvisioning
{
public const string SOURCE_NAME = "SPF_DOMAIN_NAME";
public static Dictionary<int, string> ApiErrorCodesMap;
static DomainNameController()
{
ApiErrorCodesMap = new Dictionary<int, string>();
ApiErrorCodesMap.Add(BusinessErrorCodes.ERROR_DOMAIN_QUOTA_LIMIT, ERROR_DOMAIN_QUOTA_EXCEEDED);
}
#region Trace Messages
public const string START_ACTIVATION_MSG = "Starting domain name activation";
public const string START_SUSPENSION_MSG = "Starting domain name suspension";
public const string START_CANCELLATION_MSG = "Starting domain name cancellation";
public const string START_ROLLBACK_MSG = "Trying rollback operation";
public const string TLD_PROVISIONED_MSG = "Domain name has been provisioned";
#endregion
#region Error Messages
public const string ERROR_UPDATE_USR_SETTINGS_MSG = "Could not update user settings";
public const string ERROR_ADD_INTERNAL_DOMAIN = "Could not add internal domain";
public const string ERROR_DOMAIN_QUOTA_EXCEEDED = "Domain quota has been exceeded in the customer's hosting plan";
public const string ERROR_ROLLBACK_DOM_MSG = "Could not rollback added internal domain";
#endregion
protected DomainNameSvc GetDomainNameSvc(int serviceId)
{
// assemble svc instance
DomainNameSvc domainSvc = ObjectUtils.FillObjectFromDataReader<DomainNameSvc>(
EcommerceProvider.GetDomainNameSvc(SecurityContext.User.UserId, serviceId));
// deserialize svc properties
SecurityUtils.DeserializeGenericProfile(domainSvc.PropertyNames, domainSvc.PropertyValues, domainSvc);
// return result
return domainSvc;
}
protected InvoiceItem GetDomainSvcSetupFee(DomainNameSvc service)
{
InvoiceItem line = new InvoiceItem();
line.ItemName = service.ServiceName;
line.Quantity = 1;
line.UnitPrice = service.SetupFee;
line.TypeName = "Setup Fee";
return line;
}
protected InvoiceItem GetDomainSvcFee(DomainNameSvc service)
{
InvoiceItem line = new InvoiceItem();
line.ItemName = service.ServiceName;
line.ServiceId = service.ServiceId;
line.Quantity = 1;
line.UnitPrice = service.RecurringFee;
// define line type
if (service.Status != ServiceStatus.Ordered)
{
line.TypeName = "Recurring Fee";
}
else
{
switch (service["SPF_ACTION"])
{
case DomainNameSvc.SPF_TRANSFER_ACTION:
line.TypeName = String.Concat(Product.TOP_LEVEL_DOMAIN_NAME, " Transfer");
break;
case DomainNameSvc.SPF_REGISTER_ACTION:
line.TypeName = String.Concat(Product.TOP_LEVEL_DOMAIN_NAME, " Registration");
break;
}
}
return line;
}
#region IServiceProvisioning Members
public ServiceHistoryRecord[] GetServiceHistory(int serviceId)
{
List<ServiceHistoryRecord> history = ObjectUtils.CreateListFromDataReader<ServiceHistoryRecord>(
EcommerceProvider.GetDomainNameSvcHistory(SecurityContext.User.UserId, serviceId));
//
if (history != null)
return history.ToArray();
//
return new ServiceHistoryRecord[] { };
}
public InvoiceItem[] CalculateInvoiceLines(int serviceId)
{
List<InvoiceItem> lines = new List<InvoiceItem>();
//
DomainNameSvc domainSvc = GetDomainNameSvc(serviceId);
//
if (domainSvc["SPF_ACTION"] != DomainNameSvc.SPF_UPDATE_NS_ACTION)
{
// domain svc fee
lines.Add(GetDomainSvcFee(domainSvc));
// setup fee
if (domainSvc.SetupFee > 0M && domainSvc.Status == ServiceStatus.Ordered)
lines.Add(GetDomainSvcSetupFee(domainSvc));
}
//
return lines.ToArray();
}
public Service GetServiceInfo(int serviceId)
{
return GetDomainNameSvc(serviceId);
}
public int UpdateServiceInfo(Service serviceInfo)
{
DomainNameSvc domainSvc = (DomainNameSvc)serviceInfo;
// serialize props & values
string propertyNames = null;
string propertyValues = null;
SecurityUtils.SerializeGenericProfile(ref propertyNames, ref propertyValues, domainSvc);
// update svc
return EcommerceProvider.UpdateDomainNameSvc(SecurityContext.User.UserId, domainSvc.ServiceId,
domainSvc.ProductId, (int)domainSvc.Status, domainSvc.DomainId, domainSvc.Fqdn,
propertyNames, propertyValues);
}
public int AddServiceInfo(string contractId, string currency, OrderItem orderItem)
{
string propertyNames = null;
string propertyValues = null;
// deserialize
SecurityUtils.SerializeGenericProfile(ref propertyNames, ref propertyValues, orderItem);
//
return EcommerceProvider.AddDomainNameSvc(contractId, orderItem.ParentSvcId,
orderItem.ProductId, orderItem.ItemName, orderItem.BillingCycle, currency, propertyNames, propertyValues);
}
public GenericSvcResult ActivateService(ProvisioningContext context)
{
GenericSvcResult result = new GenericSvcResult();
// remeber svc state
SaveObjectState(SERVICE_INFO, context.ServiceInfo);
// concretize service to be provisioned
DomainNameSvc domainSvc = (DomainNameSvc)context.ServiceInfo;
// concretize parent service
HostingPackageSvc packageSvc = (HostingPackageSvc)context.ParentSvcInfo;
try
{
// LOG INFO
TaskManager.StartTask(SystemTasks.SOURCE_ECOMMERCE, SystemTasks.SVC_ACTIVATE);
TaskManager.WriteParameter(CONTRACT_PARAM, domainSvc.ContractId);
TaskManager.WriteParameter(SVC_PARAM, domainSvc.ServiceName);
TaskManager.WriteParameter(SVC_ID_PARAM, domainSvc.ServiceId);
// 0. Do security checks
if (!CheckOperationClientPermissions(result))
{
// LOG ERROR
TaskManager.WriteError(ERROR_CLIENT_OPERATION_PERMISSIONS);
TaskManager.WriteParameter(RESULT_CODE_PARAM, result.ResultCode);
// EXIT
return result;
}
//
if (!CheckOperationClientStatus(result))
{
// LOG ERROR
TaskManager.WriteError(ERROR_CLIENT_OPERATION_STATUS);
TaskManager.WriteParameter(RESULT_CODE_PARAM, result.ResultCode);
// EXIT
return result;
}
// error: hosting addon should have parent svc assigned
if (packageSvc == null || packageSvc.PackageId == 0)
{
result.Succeed = false;
//
result.Error = PARENT_SVC_NOT_FOUND_MSG;
//
result.ResultCode = EcommerceErrorCodes.ERROR_PARENT_SVC_NOT_FOUND;
// LOG ERROR
TaskManager.WriteError(result.Error);
TaskManager.WriteParameter(RESULT_CODE_PARAM, result.ResultCode);
// EXIT
return result;
}
// first of all - create internal domain in WebsitePanel
if (domainSvc.Status == ServiceStatus.Ordered)
{
// create domain info object
DomainInfo domain = ServerController.GetDomain(domainSvc.Fqdn);
//
if (domain != null)
domainSvc.DomainId = domain.DomainId;
//
if (domain == null)
{
domain = new DomainInfo();
domain.DomainName = domainSvc.Fqdn;
domain.HostingAllowed = false;
domain.PackageId = packageSvc.PackageId;
// add internal domain
domainSvc.DomainId = ServerController.AddDomain(domain);
// check API result
if (domainSvc.DomainId < 1)
{
// ASSEMBLE ERROR
result.Succeed = false;
// try to find corresponding error code->error message mapping
if (ApiErrorCodesMap.ContainsKey(domainSvc.DomainId))
result.Error = ApiErrorCodesMap[domainSvc.DomainId];
else
result.Error = ERROR_ADD_INTERNAL_DOMAIN;
// copy result code
result.ResultCode = domainSvc.DomainId;
// LOG ERROR
TaskManager.WriteError(result.Error);
TaskManager.WriteParameter(RESULT_CODE_PARAM, result.ResultCode);
// EXIT
return result;
}
}
}
// update nameservers only
if (domainSvc["SPF_ACTION"] == "UPDATE_NS")
{
// remove service here...
ServiceController.DeleteCustomerService(domainSvc.ServiceId);
//
result.Succeed = true;
// EXIT
return result;
}
// load registrar wrapper
IDomainRegistrar registrar = (IDomainRegistrar)SystemPluginController.GetSystemPluginInstance(
domainSvc.ContractId, domainSvc.PluginId, true);
#region Commented operations
// prepare consumer account information
/*CommandParams cmdParams = PrepeareAccountParams(context.ConsumerInfo);
// copy svc properties
foreach (string keyName in domainSvc.GetAllKeys())
cmdParams[keyName] = domainSvc[keyName];
// check registrar requires sub-account to be created
if (registrar.SubAccountRequired)
{
// 1. Load user's settings
UserSettings userSettings = LoadUserSettings(context.ConsumerInfo.UserId, registrar.PluginName);
// 2. Ensure user has account on registrar's side
if (userSettings.SettingsArray == null || userSettings.SettingsArray.Length == 0)
{
// 3. Check account exists
bool exists = registrar.CheckSubAccountExists(context.ConsumerInfo.Username, context.ConsumerInfo.Email);
//
AccountResult accResult = null;
//
if (!exists)
{
// 4. Create user account
accResult = registrar.CreateSubAccount(cmdParams);
// copy keys & values
foreach (string keyName in accResult.AllKeys)
{
userSettings[keyName] = accResult[keyName];
}
}
else
{
// 4a. Get sub-account info
accResult = registrar.GetSubAccount(context.ConsumerInfo.Username,
context.ConsumerInfo.Email);
//
foreach (string keyName in accResult.AllKeys)
userSettings[keyName] = accResult[keyName];
}
// 5. Update user settings
int apiResult = UserController.UpdateUserSettings(userSettings);
// check API result
if (apiResult < 0)
{
// BUILD ERROR
result.Error = ERROR_UPDATE_USR_SETTINGS_MSG;
result.Succeed = false;
result.ResultCode = apiResult;
// LOG ERROR
TaskManager.WriteError(result.Error);
TaskManager.WriteParameter(RESULT_CODE_PARAM, result.ResultCode);
// ROLLBACK
RollbackOperation(domainSvc.DomainId);
// EXIT
return result;
}
}
// copy registrar-specific data
foreach (string[] pair in userSettings.SettingsArray)
{
// copy 2
cmdParams[pair[0]] = pair[1];
}
}*/
#endregion
// load NS settings
PackageSettings nsSettings = PackageController.GetPackageSettings(packageSvc.PackageId, PackageSettings.NAME_SERVERS);
// build name servers array
string[] nameServers = null;
if (!String.IsNullOrEmpty(nsSettings[PackageSettings.NAME_SERVERS]))
nameServers = nsSettings[PackageSettings.NAME_SERVERS].Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries);
// register or renew domain
if (domainSvc.Status == ServiceStatus.Ordered)
// try to register domain
registrar.RegisterDomain(domainSvc, context.ConsumerInfo, nameServers);
else
// try to renew domain
registrar.RenewDomain(domainSvc, context.ConsumerInfo, nameServers);
// change svc status to active
domainSvc.Status = ServiceStatus.Active;
// update service info
int updResult = UpdateServiceInfo(domainSvc);
// check update result for errors
if (updResult < 0)
{
// BUILD ERROR
result.ResultCode = updResult;
result.Succeed = false;
result.Error = ERROR_SVC_UPDATE_MSG;
// LOG ERROR
TaskManager.WriteError(result.Error);
TaskManager.WriteParameter(RESULT_CODE_PARAM, result.ResultCode);
// ROLLBACK
RollbackOperation(domainSvc.DomainId);
// EXIT
return result;
}
//
result.Succeed = true;
//
SetOutboundParameters(context);
}
catch (Exception ex)
{
// LOG ERROR
TaskManager.WriteError(ex);
result.Succeed = false;
// ROLLBACK
RollbackOperation(result.ResultCode);
}
finally
{
TaskManager.CompleteTask();
}
//
return result;
}
public GenericSvcResult SuspendService(ProvisioningContext context)
{
GenericSvcResult result = new GenericSvcResult();
//
result.Succeed = true;
//
DomainNameSvc service = (DomainNameSvc)context.ServiceInfo;
service.Status = ServiceStatus.Suspended;
//
UpdateServiceInfo(service);
//
SetOutboundParameters(context);
//
return result;
}
public GenericSvcResult CancelService(ProvisioningContext context)
{
GenericSvcResult result = new GenericSvcResult();
//
result.Succeed = true;
//
DomainNameSvc service = (DomainNameSvc)context.ServiceInfo;
service.Status = ServiceStatus.Cancelled;
//
UpdateServiceInfo(service);
//
SetOutboundParameters(context);
//
return result;
}
public void LogServiceUsage(ProvisioningContext context)
{
// concretize svc to be provisioned
DomainNameSvc domainSvc = (DomainNameSvc)context.ServiceInfo;
//
base.LogServiceUsage(context.ServiceInfo, domainSvc.SvcCycleId,
domainSvc.BillingPeriod, domainSvc.PeriodLength);
}
#endregion
private void RollbackOperation(int domainId)
{
if (domainId < 1)
return;
try
{
// restore
DomainNameSvc domainSvc = (DomainNameSvc)RestoreObjectState(SERVICE_INFO);
int apiResult = 0;
switch (domainSvc.Status)
{
// Service
case ServiceStatus.Ordered:
apiResult = ServerController.DeleteDomain(domainId);
break;
}
// check API result
if (apiResult < 0)
{
// LOG ERROR
TaskManager.WriteError(ERROR_ROLLBACK_DOM_MSG);
TaskManager.WriteParameter(RESULT_CODE_PARAM, apiResult);
}
// rollback service changes in EC metabase
apiResult = UpdateServiceInfo(domainSvc);
// check API result
if (apiResult < 0)
{
// LOG ERROR
TaskManager.WriteError(ERROR_ROLLBACK_SVC_MSG);
TaskManager.WriteParameter(RESULT_CODE_PARAM, apiResult);
// EXIT
return;
}
//
TaskManager.Write(ROLLBACK_SUCCEED_MSG);
}
catch (Exception ex)
{
TaskManager.WriteError(ex);
}
}
/// <summary>
/// Loads user's plugin-specific settings
/// </summary>
/// <param name="userId"></param>
/// <param name="pluginName"></param>
/// <returns></returns>
private UserSettings LoadUserSettings(int userId, string pluginName)
{
// build settings name
string settingsName = pluginName + "Settings";
// load user settings
UserSettings settings = UserController.GetUserSettings(userId, settingsName);
// set settings name
settings.SettingsName = settingsName;
//
return settings;
}
private CommandParams PrepeareAccountParams(UserInfo userInfo)
{
CommandParams args = new CommandParams();
args[CommandParams.USERNAME] = userInfo.Username;
args[CommandParams.PASSWORD] = userInfo.Password;
args[CommandParams.FIRST_NAME] = userInfo.FirstName;
args[CommandParams.LAST_NAME] = userInfo.LastName;
args[CommandParams.EMAIL] = userInfo.Email;
args[CommandParams.ADDRESS] = userInfo.Address;
args[CommandParams.CITY] = userInfo.City;
args[CommandParams.STATE] = userInfo.State;
args[CommandParams.COUNTRY] = userInfo.Country;
args[CommandParams.ZIP] = userInfo.Zip;
args[CommandParams.PHONE] = userInfo.PrimaryPhone;
args[CommandParams.FAX] = userInfo.Fax;
return args;
}
}
}