using System;
using System.Data;
using System.Threading;
using System.Collections;
using System.Security.Principal;
using System.Collections.Generic;
using System.Web;
using CMS.GlobalHelper;
using CMS.ResourceManager;
using CMS.SettingsProvider;
using CMS.SiteProvider;
using CMS.UIControls;
using CMS.DocumentEngine;
using CMS.EventLog;
using CMS.CMSHelper;
using CMS.DataEngine;
using CMS.LicenseProvider;
using CMS.TranslationServices;
public partial class CMSModules_Translations_Pages_TranslateDocuments : CMSTranslationServiceModalPage
{
#region "Private variables"
private string targetCulture = null;
private bool isModal = false;
private bool isSelect = false;
private readonly ArrayList nodeIds = new ArrayList();
private string[] nodeIdsArr = null;
private int cancelNodeId = 0;
private CurrentUserInfo currentUser = null;
private SiteInfo currentSite = null;
private static readonly Hashtable mErrors = new Hashtable();
private Hashtable mParameters = null;
private string currentCulture = CultureHelper.DefaultUICulture;
#endregion
#region "Properties"
///
/// Returns messages placeholder.
///
public override CMS.ExtendedControls.MessagesPlaceHolder MessagesPlaceHolder
{
get
{
return plcMessages;
}
}
///
/// Current log context.
///
public LogContext CurrentLog
{
get
{
return EnsureLog();
}
}
///
/// Current Error.
///
private string CurrentError
{
get
{
return ValidationHelper.GetString(mErrors["TranslateError_" + ctlAsync.ProcessGUID], string.Empty);
}
set
{
mErrors["TranslateError_" + ctlAsync.ProcessGUID] = value;
}
}
///
/// Indicates whether action is multiple.
///
private static bool IsMultipleAction
{
get
{
return QueryHelper.GetBoolean("multiple", false);
}
}
///
/// Where condition used for multiple actions.
///
private string WhereCondition
{
get
{
string where = string.Empty;
if (Parameters != null)
{
where = ValidationHelper.GetString(Parameters["where"], string.Empty);
}
return where;
}
}
///
/// Hashtable containing dialog parameters.
///
private Hashtable Parameters
{
get
{
if (mParameters == null)
{
string identifier = QueryHelper.GetString("params", null);
mParameters = (Hashtable)WindowHelper.GetItem(identifier);
}
return mParameters;
}
}
#endregion
#region "Page events"
protected override void OnPreInit(EventArgs e)
{
isModal = QueryHelper.GetBoolean("modal", false);
if (isModal)
{
this.MasterPageFile = "~/CMSMasterPages/UI/Dialogs/ModalSimplePage.master";
}
base.OnPreInit(e);
}
protected void Page_Load(object sender, EventArgs e)
{
// Register script files
ScriptHelper.RegisterCMS(this);
ScriptHelper.RegisterScriptFile(this, "~/CMSModules/Content/CMSDesk/Operation.js");
if (QueryHelper.ValidateHash("hash"))
{
// This is only to make sure that WebApplicationPhysicalPath is loaded when Async translation is started
string appPath = URLHelper.WebApplicationPhysicalPath;
// Set current UI culture
currentCulture = CultureHelper.PreferredUICulture;
// Initialize current user
currentUser = CMSContext.CurrentUser;
// Initialize current site
currentSite = CMSContext.CurrentSite;
if (!TranslationServiceHelper.IsTranslationAllowed(CurrentSiteName))
{
pnlContent.Visible = false;
ShowError(GetString("translations.translationnotallowed"));
return;
}
// Initialize events
ctlAsync.OnFinished += ctlAsync_OnFinished;
ctlAsync.OnError += ctlAsync_OnError;
ctlAsync.OnRequestLog += ctlAsync_OnRequestLog;
ctlAsync.OnCancel += ctlAsync_OnCancel;
targetCulture = QueryHelper.GetString("targetculture", CMSContext.PreferredCultureCode);
isSelect = QueryHelper.GetBoolean("select", false);
if (isModal)
{
RegisterModalPageScripts();
RegisterEscScript();
plcInfo.Visible = false;
pnlAsyncBody.CssClass = "DialogPageBody";
pnlTitleAsync.CssClass = "DialogsPageHeader";
pnlContent.CssClass = "PageContent";
pnlServiceSelector.CssClass = "TranslationSelectorBox";
pnlButtons.CssClass = "FloatRight PageFooterLine";
}
if (isSelect)
{
pnlDocList.Visible = false;
pnlDocSelector.Visible = true;
translationElem.DisplayMachineServices = false;
translationElem.DisplayTargetlanguage = true;
}
if (!RequestHelper.IsCallback())
{
// If not in select mode, load all the document IDs and check permissions
// In select mode, documents are checked when the button is clicked
if (!isSelect)
{
DataSet allDocs = null;
TreeProvider tree = new TreeProvider(currentUser);
// Current Node ID to translate
string parentAliasPath = string.Empty;
if (Parameters != null)
{
parentAliasPath = ValidationHelper.GetString(Parameters["parentaliaspath"], string.Empty);
nodeIdsArr = ValidationHelper.GetString(Parameters["nodeids"], string.Empty).Trim('|').Split(new char[] { '|' }, StringSplitOptions.RemoveEmptyEntries);
}
if (string.IsNullOrEmpty(parentAliasPath))
{
if (nodeIdsArr == null)
{
string nodeIdQuery = QueryHelper.GetString("nodeid", "");
if (nodeIdQuery != "")
{
// Mode of single node translation
pnlList.Visible = false;
chkSkipTranslated.Checked = false;
translationElem.NodeID = ValidationHelper.GetInteger(nodeIdQuery, 0);
nodeIdsArr = new string[] { nodeIdQuery };
}
else
{
nodeIdsArr = new string[] { };
}
}
foreach (string nodeId in nodeIdsArr)
{
int id = ValidationHelper.GetInteger(nodeId, 0);
if (id != 0)
{
nodeIds.Add(id);
}
}
}
else
{
string where = WhereCondition;
allDocs = tree.SelectNodes(currentSite.SiteName, parentAliasPath.TrimEnd(new char[] { '/' }) + "/%",
TreeProvider.ALL_CULTURES, true, TreeProvider.ALL_CLASSNAMES, where,
"DocumentName", TreeProvider.ALL_LEVELS, false, 0,
TreeProvider.SELECTNODES_REQUIRED_COLUMNS + ",DocumentName,NodeParentID,NodeSiteID,NodeAliasPath");
if (!DataHelper.DataSourceIsEmpty(allDocs))
{
foreach (DataTable table in allDocs.Tables)
{
foreach (DataRow row in table.Rows)
{
nodeIds.Add(ValidationHelper.GetInteger(row["NodeID"], 0));
}
}
}
}
if (nodeIds.Count > 0)
{
// Set the target settings
translationElem.TranslationSettings = new TranslationSettings()
{
TargetLanguage = targetCulture
};
string where = "NodeID IN (";
foreach (int nodeID in nodeIds)
{
where += nodeID + ",";
}
where = where.TrimEnd(',') + ")";
DataSet ds = allDocs ?? tree.SelectNodes(currentSite.SiteName, "/%", TreeProvider.ALL_CULTURES, true, null, where, "DocumentName", -1, false);
if (!DataHelper.DataSourceIsEmpty(ds))
{
TreeNode node = null;
string docList = null;
if (string.IsNullOrEmpty(parentAliasPath))
{
cancelNodeId = ValidationHelper.GetInteger(DataHelper.GetDataRowValue(ds.Tables[0].Rows[0], "NodeParentID"), 0);
}
else
{
cancelNodeId = TreePathUtils.GetNodeIdByAliasPath(currentSite.SiteName, parentAliasPath);
}
foreach (DataTable table in ds.Tables)
{
foreach (DataRow dr in table.Rows)
{
bool isLink = (dr["NodeLinkedNodeID"] != DBNull.Value);
string name = (string)dr["DocumentName"];
docList += HTMLHelper.HTMLEncode(name);
if (isLink)
{
docList += UIHelper.GetDocumentMarkImage(Page, DocumentMarkEnum.Link);
}
docList += "
";
lblDocuments.Text = docList;
// Set visibility of checkboxes
node = TreeNode.New(dr, ValidationHelper.GetString(dr["ClassName"], string.Empty));
if (!IsUserAuthorizedToTranslateDocument(node, currentSite.SiteName, targetCulture))
{
HideUI();
plcMessages.AddError(String.Format(GetString("cmsdesk.notauthorizedtotranslatedocument"), HTMLHelper.HTMLEncode(node.NodeAliasPath)), null);
}
}
}
}
// Display check box for separate submissions for each document if there is more than one document
chkSeparateSubmissions.Visible = (nodeIds.Count > 1);
}
else
{
// Hide everything
pnlContent.Visible = false;
}
}
// Setup page title text and image
CurrentMaster.Title.TitleText = GetString("Content.TranslateTitle");
CurrentMaster.Title.TitleImage = GetImageUrl("CMSModules/CMS_Content/Dialogs/translate.png");
if (isSelect)
{
CurrentMaster.Title.HelpTopicName = "translationservices_translatedocuments";
}
else
{
CurrentMaster.Title.HelpTopicName = "translationservices_createsubmission";
}
btnCancel.Text = GetString("general.cancel");
btnCancel.Attributes.Add("onclick", ctlAsync.GetCancelScript(true) + "return false;");
// Register the dialog script
ScriptHelper.RegisterDialogScript(this);
titleElemAsync.TitleText = GetString("ContentTranslate.TranslatingDocuments");
titleElemAsync.TitleImage = GetImageUrl("CMSModules/CMS_Content/Dialogs/translate.png");
// Set visibility of panels
pnlContent.Visible = true;
pnlLog.Visible = false;
}
}
else
{
pnlContent.Visible = false;
ShowError(GetString("dialogs.badhashtext"));
}
}
private void HideUI()
{
pnlButtons.Visible = false;
pnlSettings.Visible = false;
pnlList.Visible = false;
plcInfo.Visible = false;
}
protected override void OnPreRender(EventArgs e)
{
if (!translationElem.SourceCultureAvailable)
{
pnlSettings.Visible = false;
btnOk.Visible = false;
ShowError(GetString("translations.nosourceculture"));
}
if (translationElem.DisplayedServicesCount == 1)
{
lblSelectTranslationService.ResourceString = null;
lblSelectTranslationService.Text = translationElem.DisplayedServiceName;
}
string refreshCurrent = null;
if (isModal)
{
btnNo.OnClientClick = "CloseDialog(); return false";
refreshCurrent = "function RefreshCurrent(){ CloseDialog(); RefreshTree(" + cancelNodeId + "," + cancelNodeId + ");}";
}
else
{
btnNo.OnClientClick = "SelectNode(" + cancelNodeId + "); return false";
refreshCurrent = "function RefreshCurrent(){ RefreshTree(" + cancelNodeId + "," + cancelNodeId + "); }";
}
ScriptHelper.RegisterClientScriptBlock(this, typeof(string), "refreshCurrent", ScriptHelper.GetScript(refreshCurrent));
base.OnPreRender(e);
}
#endregion
#region "Button actions"
protected void btnTranslate_Click(object sender, EventArgs e)
{
if (isSelect)
{
// If in select mode, prepare node IDs now
TreeProvider tree = new TreeProvider(currentUser);
DataSet ds = tree.SelectNodes(CurrentSiteName, pathElem.Value.ToString(), TreeProvider.ALL_CULTURES, true, TreeProvider.ALL_CLASSNAMES, null,
"DocumentName", TreeProvider.ALL_LEVELS, false, 0, TreeProvider.SELECTNODES_REQUIRED_COLUMNS + ",DocumentName,NodeParentID,NodeSiteID,NodeAliasPath");
if (!DataHelper.DataSourceIsEmpty(ds))
{
foreach (DataTable table in ds.Tables)
{
foreach (DataRow dr in table.Rows)
{
TreeNode node = TreeNode.New(dr, ValidationHelper.GetString(dr["ClassName"], string.Empty));
if (IsUserAuthorizedToTranslateDocument(node, currentSite.SiteName, translationElem.TargetLanguage))
{
nodeIds.Add(ValidationHelper.GetInteger(dr["NodeID"], 0));
}
else
{
HideUI();
plcMessages.AddError(String.Format(GetString("cmsdesk.notauthorizedtotranslatedocument"), HTMLHelper.HTMLEncode(node.NodeAliasPath)), null);
return;
}
}
}
}
else
{
ShowError(GetString("translationservice.nodocumentstotranslate"));
return;
}
targetCulture = translationElem.TargetLanguage;
}
pnlLog.Visible = true;
pnlContent.Visible = false;
CurrentError = string.Empty;
CurrentLog.Close();
EnsureLog();
ctlAsync.Parameter = currentUser.PreferredCultureCode + ";" + currentSite.SiteName;
ctlAsync.RunAsync(Translate, WindowsIdentity.GetCurrent());
}
#endregion
#region "Async methods"
///
/// Translates document(s).
///
private void Translate(object parameter)
{
if (parameter == null || nodeIds.Count < 1)
{
return;
}
int refreshId = 0;
TreeProvider tree = new TreeProvider(currentUser);
tree.AllowAsyncActions = false;
try
{
// Begin log
AddLog(ResHelper.GetString("contentrequest.starttranslate", currentCulture));
bool oneSubmission = chkSeparateSubmissions.Checked;
// Prepare translation settings
TranslationSettings settings = new TranslationSettings();
settings.TargetLanguage = targetCulture;
settings.TranslateWebpartProperties = SettingsKeyProvider.GetBoolValue(CMSContext.CurrentSiteName + ".CMSTranslateWebpartProperties");
settings.SourceLanguage = translationElem.FromLanguage;
settings.Instructions = translationElem.Instructions;
settings.Priority = translationElem.Priority;
settings.TranslateAttachments = translationElem.ProcessBinary;
settings.ProcessBinary = translationElem.ProcessBinary;
settings.TranslationDeadline = translationElem.Deadline;
settings.TranslationServiceName = translationElem.SelectedService;
using (CMSTransactionScope tr = new CMSTransactionScope())
{
// Get the translation provider
AbstractMachineTranslationService machineService = null;
AbstractHumanTranslationService humanService = null;
TranslationSubmissionInfo submission = null;
TranslationServiceInfo ti = TranslationServiceInfoProvider.GetTranslationServiceInfo(translationElem.SelectedService);
if (ti != null)
{
// Set if we need target tag (Translations.com workaround)
settings.GenerateTargetTag = ti.TranslationServiceGenerateTargetTag;
if (oneSubmission)
{
if (ti.TranslationServiceIsMachine)
{
machineService = AbstractMachineTranslationService.GetTranslationService(ti, CurrentSiteName);
}
else
{
humanService = AbstractHumanTranslationService.GetTranslationService(ti, CurrentSiteName);
if (oneSubmission)
{
submission = TranslationServiceHelper.CreateSubmissionInfo(settings, ti, CMSContext.CurrentUser.UserID, CMSContext.CurrentSiteID, "Document submission " + DateTime.Now);
}
}
}
bool langSupported = true;
if (humanService != null)
{
if (!humanService.IsLanguageSupported(settings.TargetLanguage))
{
AddError(ResHelper.GetString("translationservice.targetlanguagenotsupported"));
langSupported = false;
}
}
if (langSupported)
{
if (!oneSubmission || (machineService != null) || (humanService != null))
{
// Prepare the where condition
string where = SqlHelperClass.GetWhereCondition("NodeID", (int[])nodeIds.ToArray(typeof(int)));
string columns = "NodeID, NodeAliasPath, DocumentCulture, NodeParentID";
string submissionFileName = "";
string submissionName = "";
int charCount = 0;
int wordCount = 0;
int docCount = 0;
// Get the documents in target culture to be able to check if "Skip already translated" option is on
// Combine both, source and target culture (at least one hit has to be found - to find the source of translation)
where = SqlHelperClass.AddWhereCondition(where, "DocumentCulture = N'" + settings.SourceLanguage + "' OR DocumentCulture = N'" + settings.TargetLanguage + "'");
DataSet ds = tree.SelectNodes(CMSContext.CurrentSiteName, "/%", TreeProvider.ALL_CULTURES, true, null, where, "NodeAliasPath DESC", TreeProvider.ALL_LEVELS, false, 0, columns);
if (!DataHelper.DataSourceIsEmpty(ds))
{
List processedNodes = new List();
// Translate the documents
foreach (DataRow dr in ds.Tables[0].Rows)
{
refreshId = ValidationHelper.GetInteger(dr["NodeParentID"], 0);
int nodeId = ValidationHelper.GetInteger(dr["NodeID"], 0);
if (!processedNodes.Contains(nodeId))
{
processedNodes.Add(nodeId);
string aliasPath = ValidationHelper.GetString(dr["NodeAliasPath"], "");
string culture = ValidationHelper.GetString(dr["DocumentCulture"], "");
if (chkSkipTranslated.Checked)
{
if (culture == settings.TargetLanguage)
{
// Document already exists in requested culture, skip it
AddLog(string.Format(ResHelper.GetString("content.translatedalready"), HTMLHelper.HTMLEncode(aliasPath + " (" + culture + ")")));
continue;
}
}
// Get document in source language
TreeNode node = DocumentHelper.GetDocument(nodeId, settings.SourceLanguage, true, null);
if (node == null)
{
// Document doesn't exist in source culture, skip it
continue;
}
AddLog(string.Format(ResHelper.GetString("content.translating"), HTMLHelper.HTMLEncode(aliasPath + " (" + culture + ")")));
// Save the first document as a base for submission name
if (string.IsNullOrEmpty(submissionName))
{
submissionName = node.GetDocumentName();
}
if (string.IsNullOrEmpty(submissionFileName))
{
submissionFileName = node.NodeAlias;
}
docCount++;
// Submit the document
if (machineService != null)
{
TranslationServiceHelper.Translate(machineService, settings, node);
}
else
{
if (oneSubmission && (humanService != null))
{
TreeNode targetNode = TranslationServiceHelper.CreateTargetCultureNode(node, settings.TargetLanguage, true, false, !settings.TranslateAttachments);
TranslationSubmissionItemInfo submissionItem = TranslationServiceHelper.CreateSubmissionItemInfo(settings, submission, node, targetNode.DocumentID);
charCount += submissionItem.SubmissionItemCharCount;
wordCount += submissionItem.SubmissionItemWordCount;
}
else
{
TranslationServiceHelper.SubmitToTranslation(settings, node, out submission);
}
}
}
}
if (docCount > 0)
{
if (oneSubmission && (humanService != null))
{
AddLog(ResHelper.GetString("content.submitingtranslation"));
// Set submission name
int itemCount = processedNodes.Count;
if (itemCount > 1)
{
submissionName += " " + string.Format(GetString("translationservices.submissionnamesuffix"), itemCount - 1);
}
submission.SubmissionName = submissionName;
submission.SubmissionCharCount = charCount;
submission.SubmissionWordCount = wordCount;
submission.SubmissionItemCount = itemCount;
submission.SubmissionParameter = submissionFileName;
string err = humanService.CreateSubmission(submission);
if (!string.IsNullOrEmpty(err))
{
AddError(err);
}
// Save submission with ticket
TranslationSubmissionInfoProvider.SetTranslationSubmissionInfo(submission);
}
}
else
{
TranslationSubmissionInfoProvider.DeleteTranslationSubmissionInfo(submission);
AddError(ResHelper.GetString("TranslateDocument.DocumentsAlreadyTranslated", currentCulture));
}
}
}
else
{
AddError(ResHelper.GetString("TranslateDocument.TranslationServiceNotFound", currentCulture));
}
}
}
tr.Commit();
}
}
catch (ThreadAbortException ex)
{
string state = ValidationHelper.GetString(ex.ExceptionState, string.Empty);
if (state == CMSThread.ABORT_REASON_STOP)
{
// When canceled
AddError(ResHelper.GetString("TranslateDocument.TranslationCanceled", currentCulture));
}
else
{
// Log error
LogExceptionToEventLog(ex);
}
}
catch (Exception ex)
{
// Log error
LogExceptionToEventLog(ex);
}
finally
{
if (isModal)
{
ctlAsync.Parameter = "wopener.location.replace(wopener.location); CloseDialog(); wopener.RefreshTree(null, null);";
}
else
{
if (string.IsNullOrEmpty(CurrentError))
{
// Refresh tree
ctlAsync.Parameter = "RefreshTree(" + refreshId + ", " + refreshId + "); \n" + "SelectNode(" + refreshId + ");";
}
else
{
ctlAsync.Parameter = "RefreshTree(null, null);";
}
}
}
}
#endregion
#region "Help methods"
///
/// When exception occures, log it to event log.
///
/// Exception to log
private void LogExceptionToEventLog(Exception ex)
{
EventLogProvider log = new EventLogProvider();
log.LogEvent(EventLogProvider.EVENT_TYPE_ERROR, DateTime.Now, "Content", "TRANSLATEDOC", currentUser.UserID, currentUser.UserName, 0, null, HTTPHelper.UserHostAddress, EventLogProvider.GetExceptionLogMessage(ex), currentSite.SiteID, HTTPHelper.GetAbsoluteUri());
AddError(ResHelper.GetString("ContentRequest.TranslationFailed", currentCulture) + ": " + ex.Message);
}
///
/// Adds the script to the output request window.
///
/// Script to add
public override void AddScript(string script)
{
ltlScript.Text += ScriptHelper.GetScript(script);
}
///
/// Checks whether the user is authorized to translate document.
///
/// Document node
/// Site name
/// Culture code of the document which should be checked
protected bool IsUserAuthorizedToTranslateDocument(TreeNode node, string siteName, string targetCulture)
{
// Check create permission for document
return (currentUser.IsAuthorizedPerDocument(node, new NodePermissionsEnum[] { NodePermissionsEnum.Create, NodePermissionsEnum.Read }, true, targetCulture) == AuthorizationResultEnum.Allowed) &&
(currentUser.IsAuthorizedPerResource("CMS.Content", "SubmitForTranslation"));
}
#endregion
#region "Handling async thread"
private void ctlAsync_OnCancel(object sender, EventArgs e)
{
ctlAsync.Parameter = null;
string canceled = GetString("TranslateDocument.TranslationCanceled");
AddLog(canceled);
ShowConfirmation(canceled);
ltlScript.Text += ScriptHelper.GetScript("var __pendingCallbacks = new Array();RefreshCurrent();");
if (!String.IsNullOrEmpty(CurrentError))
{
ShowError(CurrentError);
}
CurrentLog.Close();
}
private void ctlAsync_OnRequestLog(object sender, EventArgs e)
{
ctlAsync.Log = CurrentLog.Log;
}
private void ctlAsync_OnError(object sender, EventArgs e)
{
if (ctlAsync.Status == AsyncWorkerStatusEnum.Running)
{
ctlAsync.Stop();
}
ctlAsync.Parameter = null;
ShowError(CurrentError);
CurrentLog.Close();
}
private void ctlAsync_OnFinished(object sender, EventArgs e)
{
ShowError(CurrentError);
CurrentLog.Close();
if (!string.IsNullOrEmpty(CurrentError))
{
ctlAsync.Parameter = null;
ShowError(CurrentError);
}
if (ctlAsync.Parameter != null)
{
AddScript(ctlAsync.Parameter.ToString());
// Do not set the window title anymore
CurrentMaster.Title.SetWindowTitle = false;
}
}
///
/// Ensures the logging context.
///
protected LogContext EnsureLog()
{
LogContext log = LogContext.EnsureLog(ctlAsync.ProcessGUID);
log.Reversed = true;
log.LineSeparator = "
";
return log;
}
///
/// Adds the log information.
///
/// New log information
protected void AddLog(string newLog)
{
EnsureLog();
LogContext.AppendLine(newLog);
}
///
/// Adds the error to collection of errors.
///
/// Error message
protected void AddError(string error)
{
AddLog(error);
CurrentError = (error + "
" + CurrentError);
}
#endregion
}