From 2c448f87ab81b5edb8c2e047f6908de73f56f400 Mon Sep 17 00:00:00 2001
From: Jasmin Dizdarevic <jasmin.dizdarevic@gmail.com>
Date: Thu, 6 Jan 2011 20:20:31 +0100
Subject: [PATCH] UI Changes for pgAgent 4. Email notification and SQL-File (step kind) support added.

Signed-off-by: Jasmin Dizdarevic <jasmin.dizdarevic@gmail.com>
---
 pgadmin/agent/dlgJob.cpp       |   79 +++++++++++++++++++++++++++++++++++-----
 pgadmin/agent/dlgStep.cpp      |    6 ++--
 pgadmin/agent/pgaJob.cpp       |   54 ++++++++++++++++++++++-----
 pgadmin/agent/pgaStep.cpp      |    3 ++
 pgadmin/db/pgConn.cpp          |   48 ++++++++++++++++++++++++
 pgadmin/include/agent/pgaJob.h |   18 +++++++++-
 pgadmin/include/db/pgConn.h    |    4 ++
 pgadmin/ui/dlgJob.xrc          |   32 +++++++++++++++-
 pgadmin/ui/dlgStep.xrc         |    3 +-
 9 files changed, 221 insertions(+), 26 deletions(-)

diff --git a/pgadmin/agent/dlgJob.cpp b/pgadmin/agent/dlgJob.cpp
index 7f97938..06dca7d 100644
--- a/pgadmin/agent/dlgJob.cpp
+++ b/pgadmin/agent/dlgJob.cpp
@@ -26,6 +26,8 @@
 #define	txtID				CTRL_TEXT("txtID")
 #define chkEnabled          CTRL_CHECKBOX("chkEnabled")
 #define cbJobclass          CTRL_COMBOBOX("cbJobclass")
+#define txtEmailNotRecp		CTRL_TEXT("txtEmailNotRecp") 
+#define cbEmailNotType		CTRL_COMBOBOX("cbEmailNotType") 
 #define txtHostAgent        CTRL_TEXT("txtHostAgent")
 #define txtCreated          CTRL_TEXT("txtCreated")
 #define txtChanged          CTRL_TEXT("txtChanged")
@@ -47,7 +49,9 @@
 BEGIN_EVENT_TABLE(dlgJob, dlgAgentProperty)
 	EVT_CHECKBOX(XRCID("chkEnabled"),               dlgProperty::OnChange)
 	EVT_COMBOBOX(XRCID("cbJobclass"),               dlgProperty::OnChange)
+	EVT_COMBOBOX(XRCID("cbEmailNotType"),           dlgProperty::OnChange)
 	EVT_TEXT(XRCID("txtHostAgent"),                 dlgProperty::OnChange)
+	EVT_TEXT(XRCID("txtEmailNotRecp"),              dlgProperty::OnChange)
 
 	EVT_LIST_ITEM_SELECTED(XRCID("lstSteps"),       dlgJob::OnSelChangeStep)
 	EVT_BUTTON(XRCID("btnChangeStep"),              dlgJob::OnChangeStep)
@@ -131,6 +135,25 @@ int dlgJob::Go(bool modal)
 		}
 		delete jcl;
 	}
+	if(connection->pgAgentMinimumSchemaVersion(4)) 
+	{
+		pgSet *mnk = connection->ExecuteSet(wxT("SELECT jmntypename FROM pgagent.pga_jobmailnottype"));
+		if(mnk) 
+		{
+			while(!mnk->Eof()) 
+			{				
+				cbEmailNotType->Append(mnk->GetVal(0));				
+				mnk->MoveNext();
+			}
+			delete mnk;
+		}
+				
+	}
+	else 
+	{
+		txtEmailNotRecp->Disable();
+		cbEmailNotType->Disable();
+	}
 
 	if (job)
 	{
@@ -146,6 +169,10 @@ int dlgJob::Go(bool modal)
 		txtLastrun->SetValue(DateToStr(job->GetLastrun()));
 		txtLastresult->SetValue(job->GetLastresult());
 
+		if(connection->pgAgentMinimumSchemaVersion(4)) {
+			txtEmailNotRecp->SetValue(job->GetEmailNotRecp()); 
+			cbEmailNotType->SetValue(job->GetEmailNotType());
+		}
 		wxCookieType cookie;
 		pgObject *data = 0;
 
@@ -212,6 +239,7 @@ int dlgJob::Go(bool modal)
 	{
 		// create mode
 		cbJobclass->SetSelection(0);
+		cbEmailNotType->SetSelection(0);
 		btnChangeStep->Hide();
 		btnChangeSchedule->Hide();
 	}
@@ -244,8 +272,9 @@ void dlgJob::CheckChange()
 	{
 		enable  =  txtComment->GetValue() != job->GetComment()
 		           || name != job->GetName()
-		           || chkEnabled->GetValue() != job->GetEnabled()
-		           || txtHostAgent->GetValue() != job->GetHostAgent();
+		           || chkEnabled->GetValue() != job->GetEnabled()		           
+				   || txtHostAgent->GetValue() != job->GetHostAgent()
+				   || txtEmailNotRecp->GetValue() != job->GetEmailNotRecp();
 		if (!enable)
 		{
 			enable = !GetUpdateSql().IsEmpty();
@@ -257,6 +286,12 @@ void dlgJob::CheckChange()
 
 	CheckValid(enable, !txtName->GetValue().IsEmpty(), _("Please specify name."));
 
+	if(connection->pgAgentMinimumSchemaVersion(4))
+	{
+		CheckValid(enable, !(txtEmailNotRecp->GetValue().IsEmpty() && cbEmailNotType->GetValue() != wxT("None")), _("You've specified an email notification, but no recipients"));
+		wxString pgAgentHostMail = connection->CheckpgAgentMailFeature(txtHostAgent->GetValue());
+		CheckValid(enable, (!txtEmailNotRecp->GetValue().IsEmpty() && cbEmailNotType->GetValue() != wxT("None") && pgAgentHostMail == wxT("OK")), wxString::Format(wxT("You've specified email notification, but the host agent's aren't configured properly: %s"), pgAgentHostMail));
+	}
 	EnableOK(enable);
 }
 
@@ -394,13 +429,27 @@ wxString dlgJob::GetInsertSql()
 	wxString sql;
 
 	if (!job)
-	{
-		sql = wxT("INSERT INTO pgagent.pga_job (jobid, jobjclid, jobname, jobdesc, jobenabled, jobhostagent)\n")
-		      wxT("SELECT <JobId>, jcl.jclid, ") + qtDbString(GetName()) +
-		      wxT(", ") + qtDbString(txtComment->GetValue()) + wxT(", ") + BoolToStr(chkEnabled->GetValue()) +
-		      wxT(", ") + qtDbString(txtHostAgent->GetValue()) + wxT("\n")
-		      wxT("  FROM pgagent.pga_jobclass jcl WHERE jclname=") + qtDbString(cbJobclass->GetValue()) + wxT(";\n");
-	}
+    {
+		if(connection->pgAgentMinimumSchemaVersion(4)) 
+		{
+			sql = wxT("INSERT INTO pgagent.pga_job (jobid, jobjclid, jobname, jobdesc, jobenabled, jobhostagent, jobmailnotrecp, jobmailnottype)\n")			  
+				  wxT("SELECT <JobId>, jcl.jclid, ") + qtDbString(GetName()) + 
+				  wxT(", ") + qtDbString(txtComment->GetValue()) + wxT(", ") + BoolToStr(chkEnabled->GetValue()) + 
+				  wxT(", ") + qtDbString(txtHostAgent->GetValue()) +
+				  wxT(", ") + qtDbString(txtEmailNotRecp->GetValue()) +
+				  wxT(", (SELECT jmntypeid FROM pgagent.pga_jobmailnottype WHERE jmntypename = ") + qtDbString(cbEmailNotType->GetValue()) + wxT(")\n")
+				  wxT("  FROM pgagent.pga_jobclass jcl WHERE jclname=") + qtDbString(cbJobclass->GetValue()) + wxT(";\n");
+		}
+		else 
+		{
+			sql = wxT("INSERT INTO pgagent.pga_job (jobid, jobjclid, jobname, jobdesc, jobenabled, jobhostagent)\n")			  
+				  wxT("SELECT <JobId>, jcl.jclid, ") + qtDbString(GetName()) + 
+				  wxT(", ") + qtDbString(txtComment->GetValue()) + wxT(", ") + BoolToStr(chkEnabled->GetValue()) + 
+				  wxT(", ") + qtDbString(txtHostAgent->GetValue()) + wxT("\n")				  				  
+				  wxT("  FROM pgagent.pga_jobclass jcl WHERE jclname=") + qtDbString(cbJobclass->GetValue()) + wxT(";\n");
+
+		}
+    }
 	return sql;
 }
 
@@ -445,6 +494,18 @@ wxString dlgJob::GetUpdateSql()
 				vars.Append(wxT(", "));
 			vars.Append(wxT("jobdesc = ") + qtDbString(txtComment->GetValue()));
 		}
+		if(connection->pgAgentMinimumSchemaVersion(4) && txtEmailNotRecp->GetValue() != job->GetEmailNotRecp()) 
+		{
+			if(!vars.IsEmpty())
+				vars.Append(wxT(", "));
+			vars.Append(wxT("jobmailnotrecp = ") + qtDbString(txtEmailNotRecp->GetValue()));
+		}
+		if(connection->pgAgentMinimumSchemaVersion(4) && cbEmailNotType->GetValue() != job->GetEmailNotType()) 
+		{
+			if(!vars.IsEmpty())
+				vars.Append(wxT(", "));
+			vars.Append(wxT("jobmailnottype= (SELECT jmntypeid FROM pgagent.pga_jobmailnottype WHERE jmntypename=") + qtDbString(cbEmailNotType->GetValue()) + wxT(")"));
+		}
 
 		if (!vars.IsEmpty())
 			sql = wxT("UPDATE pgagent.pga_job SET ") + vars + wxT("\n")
diff --git a/pgadmin/agent/dlgStep.cpp b/pgadmin/agent/dlgStep.cpp
index d122fbd..50843a7 100644
--- a/pgadmin/agent/dlgStep.cpp
+++ b/pgadmin/agent/dlgStep.cpp
@@ -100,7 +100,7 @@ int dlgStep::Go(bool modal)
 		}
 		delete db;
 	}
-
+	rbxKind->Enable(2, connection->pgAgentMinimumSchemaVersion(4));
 	if (step)
 	{
 		// edit mode
@@ -124,7 +124,7 @@ int dlgStep::Go(bool modal)
 				cbDatabase->SetValue(step->GetDbname());
 		}
 
-		rbxKind->SetSelection(wxString(wxT("sb")).Find(step->GetKindChar()));
+		rbxKind->SetSelection(wxString(wxT("sbf")).Find(step->GetKindChar()));
 		rbxOnError->SetSelection(wxString(wxT("fsi")).Find(step->GetOnErrorChar()));
 		sqlBox->SetText(step->GetCode());
 
@@ -272,7 +272,7 @@ wxString dlgStep::GetInsertSql()
 	if (!step)
 	{
 		wxString name = GetName();
-		wxString kind = wxT("sb")[rbxKind->GetSelection()];
+		wxString kind = wxT("sbf")[rbxKind->GetSelection()];
 		wxString onerror = wxT("fsi")[rbxOnError->GetSelection()];
 		wxString db, connstr;
 		wxString jstjobid;
diff --git a/pgadmin/agent/pgaJob.cpp b/pgadmin/agent/pgaJob.cpp
index 20b77b7..b324ce1 100644
--- a/pgadmin/agent/pgaJob.cpp
+++ b/pgadmin/agent/pgaJob.cpp
@@ -122,6 +122,17 @@ void pgaJob::ShowTreeDetail(ctlTree *browser, frmMain *form, ctlListView *proper
 		properties->AppendItem(_("Next run"), GetNextrun());
 		properties->AppendItem(_("Last run"), GetLastrun());
 		properties->AppendItem(_("Last result"), GetLastresult());
+		if(GetConnection()->pgAgentMinimumSchemaVersion(4)) 
+		{
+			properties->AppendItem(_("Email notification on"), GetEmailNotType());
+			properties->AppendItem(_("Email recipients"), GetEmailNotRecp());
+
+			if(GetEmailNotType() != wxT("None") && !GetEmailNotRecp().IsEmpty()) 
+			{
+				wxString pgAgentMailStatus = GetConnection()->CheckpgAgentMailFeature(GetHostAgent());
+				properties->AppendItem(_("pgAgent email configuration"), (pgAgentMailStatus != wxT("OK")) ? wxString::Format(wxT("Not configured on: %s"), pgAgentMailStatus) : pgAgentMailStatus);
+			}
+		}
 		if (!GetCurrentAgent().IsEmpty())
 			properties->AppendItem(_("Running at"), GetCurrentAgent());
 		else
@@ -150,16 +161,35 @@ pgObject *pgaJobFactory::CreateObjects(pgCollection *collection, ctlTree *browse
 {
 	pgaJob *job = 0;
 
-	pgSet *jobs = collection->GetConnection()->ExecuteSet(
-	                  wxT("SELECT j.*, cl.*, ag.*, sub.jlgstatus AS joblastresult ")
-	                  wxT("  FROM pgagent.pga_job j JOIN")
-	                  wxT("  pgagent.pga_jobclass cl ON cl.jclid=jobjclid LEFT OUTER JOIN")
-	                  wxT("  pgagent.pga_jobagent ag ON ag.jagpid=jobagentid LEFT OUTER JOIN")
-	                  wxT("  (SELECT DISTINCT ON (jlgjobid) jlgstatus, jlgjobid")
-	                  wxT("   FROM pgagent.pga_joblog")
-	                  wxT("  ORDER BY jlgjobid, jlgid desc) sub ON sub.jlgjobid = j.jobid ")
-	                  + restriction +
-	                  wxT("ORDER BY jobname;"));
+wxString jobSql;
+	
+	if(collection->GetConnection()->pgAgentMinimumSchemaVersion(4)) {
+		//Email notification
+		jobSql = wxT("SELECT j.*, cl.*, ag.*, sub.jlgstatus AS joblastresult, nt.jmntypename as mailnotkindname ")
+				wxT("  FROM pgagent.pga_job j JOIN")
+				wxT("  pgagent.pga_jobclass cl ON cl.jclid=jobjclid LEFT OUTER JOIN")
+				wxT("  pgagent.pga_jobagent ag ON ag.jagpid=jobagentid LEFT OUTER JOIN")
+				wxT("  (SELECT DISTINCT ON (jlgjobid) jlgstatus, jlgjobid")
+				wxT("   FROM pgagent.pga_joblog")
+				wxT("  ORDER BY jlgjobid, jlgid desc) sub ON sub.jlgjobid = j.jobid ")
+				wxT("  LEFT OUTER JOIN pgagent.pga_jobmailnottype nt ON j.jobmailnottype = nt.jmntypeid ")
+				+ restriction +
+				wxT("ORDER BY jobname;");
+	}
+	else {
+			jobSql = wxT("SELECT j.*, cl.*, ag.*, sub.jlgstatus AS joblastresult")
+				wxT("  FROM pgagent.pga_job j JOIN")
+				wxT("  pgagent.pga_jobclass cl ON cl.jclid=jobjclid LEFT OUTER JOIN")
+				wxT("  pgagent.pga_jobagent ag ON ag.jagpid=jobagentid LEFT OUTER JOIN")
+				wxT("  (SELECT DISTINCT ON (jlgjobid) jlgstatus, jlgjobid")
+				wxT("   FROM pgagent.pga_joblog")
+				wxT("  ORDER BY jlgjobid, jlgid desc) sub ON sub.jlgjobid = j.jobid ")				
+				+ restriction +
+				wxT("ORDER BY jobname;");
+	}
+	
+
+	pgSet *jobs= collection->GetConnection()->ExecuteSet(jobSql);
 
 	if (jobs)
 	{
@@ -192,6 +222,10 @@ pgObject *pgaJobFactory::CreateObjects(pgCollection *collection, ctlTree *browse
 			job->iSetNextrun(jobs->GetDateTime(wxT("jobnextrun")));
 			job->iSetLastrun(jobs->GetDateTime(wxT("joblastrun")));
 			job->iSetLastresult(status);
+			if(collection->GetConnection()->pgAgentMinimumSchemaVersion(4)) {
+				job->iSetEmailNotRecp(jobs->GetVal(wxT("jobmailnotrecp")));
+				job->iSetEmailNotType(jobs->GetVal(wxT("mailnotkindname")));
+			}
 			job->iSetCurrentAgent(jobs->GetVal(wxT("jagstation")));
 
 			if (browser)
diff --git a/pgadmin/agent/pgaStep.cpp b/pgadmin/agent/pgaStep.cpp
index 8c81d42..4ff541b 100644
--- a/pgadmin/agent/pgaStep.cpp
+++ b/pgadmin/agent/pgaStep.cpp
@@ -154,6 +154,9 @@ pgObject *pgaStepFactory::CreateObjects(pgCollection *collection, ctlTree *brows
 				case 's':
 					kinds = wxT("SQL");
 					break;
+				case 'f':
+					kinds = wxT("File");
+				break;
 			}
 			step->iSetKindChar(kindc);
 			step->iSetKind(kinds);
diff --git a/pgadmin/db/pgConn.cpp b/pgadmin/db/pgConn.cpp
index b23f46b..7720f2b 100644
--- a/pgadmin/db/pgConn.cpp
+++ b/pgadmin/db/pgConn.cpp
@@ -483,6 +483,54 @@ bool pgConn::HasFeature(int featureNo)
 	return features[featureNo];
 }
 
+bool pgConn::pgAgentMinimumSchemaVersion(const int version) {
+
+	if(schemaVersionCache < 0) 
+	{		
+		schemaVersionCache = StrToLong(ExecuteScalar(wxT("SELECT pgagent.pgagent_schema_version()")));			 
+	}
+	
+	return (schemaVersionCache >= version);
+
+}
+
+wxString pgConn::CheckpgAgentMailFeature(const wxString host) {
+	/* retuns "", if every registered agent has the required version
+	/* otherwise a list of agents, that doesn't match */
+	wxString retVal, stmt;
+	
+	if(host == wxT(""))
+	{
+		stmt = wxT("SELECT jagstation from pgagent.pga_jobagent WHERE jagemailconfigured = false");
+	}
+	else 
+	{
+		stmt = wxT("SELECT jagstation from pgagent.pga_jobagent WHERE jagemailconfigured = false AND jagstation = '") + host + wxT("'");
+	}
+	
+	pgSet *agents = ExecuteSet(stmt);
+	if(agents) {
+		if(agents->NumRows() == 0)
+		{
+			retVal = wxT("OK");
+		}
+		else {
+			while(!agents->Eof())
+			{
+				retVal += agents->GetVal(0) + wxT(", ");
+				agents->MoveNext();
+			}
+			
+			retVal = retVal.substr(0, retVal.Len()-2);
+		}
+
+		delete agents;
+	}						
+	
+	
+	return retVal;
+
+}
 
 // Encrypt a password using the appropriate encoding conversion
 wxString pgConn::EncryptPassword(const wxString &user, const wxString &password)
diff --git a/pgadmin/include/agent/pgaJob.h b/pgadmin/include/agent/pgaJob.h
index c0b0b47..5e27c4f 100644
--- a/pgadmin/include/agent/pgaJob.h
+++ b/pgadmin/include/agent/pgaJob.h
@@ -123,6 +123,22 @@ public:
 	{
 		recId = l;
 	}
+	void iSetEmailNotRecp(const wxString &s) 
+	{ 
+		emailnotrecp = s;
+	}
+	wxString GetEmailNotRecp() const 
+	{
+		return emailnotrecp; 
+	}
+	void iSetEmailNotType(const wxString &s) 
+	{ 
+		emailnottype = s; 
+	}
+	wxString GetEmailNotType() const 
+	{ 
+		return emailnottype; 
+	}
 	bool RunNow();
 
 	wxMenu *GetNewMenu();
@@ -155,7 +171,7 @@ public:
 private:
 	bool enabled;
 	wxDateTime created, changed, nextrun, lastrun;
-	wxString lastresult, jobclass, currentAgent, hostAgent;
+	wxString lastresult, jobclass, currentAgent, hostAgent, emailnotrecp, emailnottype;
 	long recId;
 };
 
diff --git a/pgadmin/include/db/pgConn.h b/pgadmin/include/db/pgConn.h
index 23d6b6e..72e8644 100644
--- a/pgadmin/include/db/pgConn.h
+++ b/pgadmin/include/db/pgConn.h
@@ -214,6 +214,8 @@ public:
 	int GetTxStatus();
 
 	bool TableHasColumn(wxString schemaname, wxString tblname, const wxString &colname);
+	bool pgAgentMinimumSchemaVersion(const int version);
+	wxString CheckpgAgentMailFeature(const wxString host);
 
 protected:
 	PGconn *conn;
@@ -252,6 +254,8 @@ private:
 	wxString save_server, save_database, save_username, save_password, save_rolename, save_applicationname;
 	int save_port, save_sslmode;
 	OID save_oid;
+	
+	int schemaVersionCache;
 };
 
 #endif
diff --git a/pgadmin/ui/dlgJob.xrc b/pgadmin/ui/dlgJob.xrc
index c7e0f13..2e27f54 100644
--- a/pgadmin/ui/dlgJob.xrc
+++ b/pgadmin/ui/dlgJob.xrc
@@ -17,10 +17,10 @@
             <object class="wxPanel" name="pnlProperties">
               <object class="wxFlexGridSizer">
                 <cols>2</cols>
-                <rows>11</rows>
+                <rows>13</rows>
                 <vgap>5</vgap>
                 <hgap>5</hgap>
-                <growablerows>10</growablerows>
+                <growablerows>12</growablerows>
                 <growablecols>1</growablecols>
                 <object class="sizeritem">
                   <object class="wxStaticText" name="stName">
@@ -92,6 +92,34 @@
                   <border>4</border>
                 </object>
                 <object class="sizeritem">
+                  <object class="wxStaticText" name="stEmailNotType">
+                    <label>Email notification on</label>
+                  </object>
+                  <flag>wxALIGN_CENTRE_VERTICAL|wxTOP|wxLEFT|wxRIGHT</flag>
+                  <border>4</border>
+                </object>
+                <object class="sizeritem">
+                  <object class="wxComboBox" name="cbEmailNotType">
+                    <content/>
+                    <style>wxCB_READONLY|wxCB_DROPDOWN</style>
+                  </object>
+                  <flag>wxEXPAND|wxALIGN_CENTER_VERTICAL|wxTOP|wxLEFT|wxRIGHT</flag>
+                  <border>4</border>
+                </object>
+                <object class="sizeritem">
+                  <object class="wxStaticText" name="stEmailNotRecp">
+                    <label>Email recipients</label>
+                  </object>
+                  <flag>wxALIGN_CENTRE_VERTICAL|wxTOP|wxLEFT|wxRIGHT</flag>
+                  <border>4</border>
+                </object>
+                <object class="sizeritem">
+                  <object class="wxTextCtrl" name="txtEmailNotRecp">
+                  </object>
+                  <flag>wxEXPAND|wxALIGN_CENTER_VERTICAL|wxTOP|wxLEFT|wxRIGHT</flag>
+                  <border>4</border>
+                </object>
+                <object class="sizeritem">
                   <object class="wxStaticText" name="stCreated">
                     <label>Created</label>
                   </object>
diff --git a/pgadmin/ui/dlgStep.xrc b/pgadmin/ui/dlgStep.xrc
index 1e6859c..eccee67 100644
--- a/pgadmin/ui/dlgStep.xrc
+++ b/pgadmin/ui/dlgStep.xrc
@@ -111,7 +111,7 @@
                   </object>
                   <flag>wxEXPAND|wxALIGN_CENTRE_VERTICAL|wxTOP|wxLEFT|wxRIGHT</flag>
                   <border>4</border>
-                </object>
+                </object>                  
                 <object class="sizeritem">
                   <object class="wxBoxSizer">
                     <orient>wxVERTICAL</orient>
@@ -157,6 +157,7 @@
                     <content>
                       <item>SQL</item>
                       <item>Batch</item>
+                      <item>File</item>                                           
                     </content>
                     <selection>0</selection>
                     <label>Kind</label>
-- 
1.7.3.1.msysgit.0

