Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/mono-tools.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNina Vyedin <nina.vyedin@gmail.com>2013-03-05 02:55:52 +0400
committerNina Vyedin <nina.vyedin@gmail.com>2013-03-05 07:54:32 +0400
commit3f3bfb6c970574d31c446318164e0a01e353e79e (patch)
tree465f86fb650b30a1fccce1a921e5cbe5153b4c73
parent01e49d3e9663c252efcef3695e7cfdf71fe6b352 (diff)
[webdoc] add the contributor plugin
-rw-r--r--webdoc/plugins/contributor-plugin/auth.css8
-rw-r--r--webdoc/plugins/contributor-plugin/edit.aspx62
-rw-r--r--webdoc/plugins/contributor-plugin/login.aspx68
-rw-r--r--webdoc/plugins/contributor-plugin/logout.aspx12
-rwxr-xr-xwebdoc/plugins/contributor-plugin/monodoc.asmx210
-rw-r--r--webdoc/plugins/contributor-plugin/server.asmx1
-rw-r--r--webdoc/plugins/contributor-plugin/server.cs366
-rw-r--r--webdoc/plugins/contributor-plugin/tables.sql21
-rw-r--r--webdoc/plugins/contributor-plugin/wiki2ecmahelper.xsl70
9 files changed, 818 insertions, 0 deletions
diff --git a/webdoc/plugins/contributor-plugin/auth.css b/webdoc/plugins/contributor-plugin/auth.css
new file mode 100644
index 00000000..4cb7a165
--- /dev/null
+++ b/webdoc/plugins/contributor-plugin/auth.css
@@ -0,0 +1,8 @@
+#login {
+ position: fixed;
+ top: 0px;
+ right: 0px;
+ float: right;
+ padding: 5px;
+}
+
diff --git a/webdoc/plugins/contributor-plugin/edit.aspx b/webdoc/plugins/contributor-plugin/edit.aspx
new file mode 100644
index 00000000..f2ad4dee
--- /dev/null
+++ b/webdoc/plugins/contributor-plugin/edit.aspx
@@ -0,0 +1,62 @@
+<%@ Assembly name="monodoc" %>
+<%@ Import Namespace="Monodoc" %>
+<%@ Import Namespace="System.Xml" %>
+<%@ Import Namespace="System.IO" %>
+<html>
+<head>
+ <script language="C#" runat=server>
+ static RootTree help_tree = RootTree.LoadTree ();
+
+ void Page_Load (object sender, EventArgs ea)
+ {
+ HttpWorkerRequest r = (HttpWorkerRequest) ((IServiceProvider)Context).GetService (typeof (HttpWorkerRequest));
+ //
+ // We need the untouched QueryString, as internally the editor uses the `@' symbol as a separator.
+ //
+ string q = Request ["link"];
+ Console.WriteLine ("QueryString: " + q);
+ try {
+ XmlNode edit_node = EditingUtils.GetNodeFromUrl ("edit:" + q, help_tree);
+ Monodoc2Wiki m2w = new Monodoc2Wiki ();
+ Console.WriteLine ("XML TO TEXT: " + edit_node.InnerText);
+ EditBuffer.Text = m2w.ProcessNode ((XmlElement) edit_node);
+ } catch (Exception e){
+ EditBuffer.Text = Request.QueryString.ToString () + e.ToString ();
+ }
+ }
+
+ void Save (object o, EventArgs a)
+ {
+
+ }
+
+ void Preview (object o, EventArgs a)
+ {
+ WikiStyleDocConverter p = new WikiStyleDocConverter (EditBuffer.Text);
+ XmlNode result = p.ParseEntireDoc ();
+
+ StringWriter sw = new StringWriter ();
+ sw.Write ("YOOHO:" + result.InnerText);
+ XmlTextWriter xw = new XmlTextWriter (sw);
+ xw.Formatting = Formatting.Indented;
+ result.WriteTo (xw);
+ xw.Close ();
+
+ TextPreview.Text = "Preview<BR>" + sw.ToString ();
+ }
+ </script>
+</head>
+
+<body>
+ <form runat=server>
+ <asp:Label id="TextPreview" runat=server/>
+ <asp:TextBox id="EditBuffer" Text="multiline" TextMode="MultiLine" runat="server" rows=15 cols=80 />
+ <p>
+ <asp:Button Text="Save Page" OnClick="Save" runat=server/>
+ <asp:Button Text="Show Preview" OnClick="Preview" runat=server/>
+ <asp:LinkButton Text="Markup Help" runat=server/>
+ <asp:LinkButton Text="Cancel" runat=server/>
+ </form>
+</body>
+
+</html> \ No newline at end of file
diff --git a/webdoc/plugins/contributor-plugin/login.aspx b/webdoc/plugins/contributor-plugin/login.aspx
new file mode 100644
index 00000000..c6762214
--- /dev/null
+++ b/webdoc/plugins/contributor-plugin/login.aspx
@@ -0,0 +1,68 @@
+<%@ Import Namespace="System.Web.Security" %>
+<html>
+<script language="C#" runat=server>
+
+ void Allow ()
+ {
+ FormsAuthentication.RedirectFromLoginPage (UserEmail.Value, false);
+ // PersistCookie.Checked);
+ }
+
+ void Login_Click (object sender, EventArgs e)
+ {
+ FormsAuthenticationTicket trust = null;
+ HttpCookie c;
+
+ switch (UserEmail.Value){
+ case "miguel":
+ trust = new FormsAuthenticationTicket ("high", false, 1);
+ c = new HttpCookie ("level", FormsAuthentication.Encrypt (trust));
+ Response.AppendCookie (c);
+ Allow ();
+ break;
+ case "guest":
+ trust = new FormsAuthenticationTicket ("low", false, 1);
+ c = new HttpCookie ("level", FormsAuthentication.Encrypt (trust));
+ Response.AppendCookie (c);
+ Allow ();
+ break;
+ default:
+ Msg.Text = "Invalid Credentials: Please try again";
+ break;
+ }
+ }
+
+ void Page_Load ()
+ {
+ Msg.Text = ">>> " + Request.QueryString ["ReturnUrl"] + "<<<";
+ }
+</script>
+<body>
+<form runat=server>
+
+ <h3><font face="Verdana">Login Page</font></h3>
+ <table>
+ <tr>
+ <td>Email:</td>
+ <td><input id="UserEmail" type="text" runat=server/></td>
+ <td><ASP:RequiredFieldValidator ControlToValidate="UserEmail"
+ Display="Static" ErrorMessage="*" runat=server/></td>
+ </tr>
+ <tr>
+ <td>Password:</td>
+ <td><input id="UserPass" type=password runat=server/></td>
+ <td><ASP:RequiredFieldValidator ControlToValidate="UserPass"
+ Display="Static" ErrorMessage="*" runat=server/></td>
+ </tr>
+ <tr>
+ <td>Persistent Cookie:</td>
+ <td><ASP:CheckBox id=PersistCookie runat="server" /> </td>
+ <td></td>
+ </tr>
+ </table>
+ <asp:button text="Login" OnClick="Login_Click" runat=server/>
+ <p>
+ <asp:Label id="Msg" ForeColor="red" Font-Name="Verdana" Font-Size="10" runat=server />
+</form>
+</body>
+</html>
diff --git a/webdoc/plugins/contributor-plugin/logout.aspx b/webdoc/plugins/contributor-plugin/logout.aspx
new file mode 100644
index 00000000..af3621be
--- /dev/null
+++ b/webdoc/plugins/contributor-plugin/logout.aspx
@@ -0,0 +1,12 @@
+<%@ Import Namespace="System.Web.Security" %>
+<html>
+<script language="C#" runat=server>
+ void Page_Load (object sender, EventArgs e)
+ {
+ FormsAuthentication.SignOut ();
+ Response.Redirect ("index.aspx");
+ }
+</script>
+<body>
+</body>
+</html>
diff --git a/webdoc/plugins/contributor-plugin/monodoc.asmx b/webdoc/plugins/contributor-plugin/monodoc.asmx
new file mode 100755
index 00000000..d8e5fd64
--- /dev/null
+++ b/webdoc/plugins/contributor-plugin/monodoc.asmx
@@ -0,0 +1,210 @@
+<%@ WebService language="C#" class="Editing" %>
+
+// MonoDoc Editing WebService
+//
+// (C) 2003 by Johannes Roith
+// Author: Johannes Roith
+
+// Client API:
+//
+// Editing edit = new Editing();
+// Response response = edit.Submit("Johannes Roith", "johannes@jroith.de",
+// "This is a change through monodoc editing.", xml);
+
+// response contains:
+// a server status message (response.Message)
+// a statuscode (response.Status)
+
+// Statuscodes:
+//
+// 1 - everything went right
+// 2 - the xml is not well-formed.
+// 3 - some data is missing (email, name, etc.).
+// 4 - the data was already posted
+// 5 - Some internal Server error
+
+
+using System;
+using System.Web.Services;
+using System.Xml.Serialization;
+using System.Xml;
+using System.Text;
+using System.Security.Cryptography;
+
+[WebService(Namespace="http://www.go-mono.org/monodoc")]
+public class Editing {
+
+ [WebMethod]
+ public Response Submit(string author, string email, string personalmessage, string xmldata) {
+
+ Response response;
+ string newsum = GetMd5Sum(xmldata);
+ XmlElement dataroot;
+ XmlDocument oldposts;
+ string today = Convert.ToString(DateTime.Now.DayOfYear);
+
+ try {
+
+
+ oldposts = new XmlDocument();
+ oldposts.Load("oldposts.xml");
+
+ dataroot = oldposts.DocumentElement;
+
+ // Eventually only block in certain time frame?
+ // XmlNodeList datanodes = dataroot.SelectNodes("/oldposts/post[@date='" + today + "']");
+
+ XmlNodeList datanodes = dataroot.SelectNodes("/oldposts/post");
+
+ foreach(XmlNode datanode in datanodes) {
+ if (datanode.Attributes["md5"].Value == newsum) {
+
+ response = new Response();
+ response.Status = 4;
+ response.Message = "This was already posted.";
+
+ return response;
+ }
+ }
+
+ if (xmldata == "")
+ {
+
+ response = new Response();
+ response.Status = 2;
+ response.Message = "Xml not well-formed. No data was posted.";
+
+ return response;
+ }
+
+ XmlDocument doc = new XmlDocument();
+ doc.LoadXml(xmldata);
+
+ XmlElement root = doc.DocumentElement;
+ XmlNodeList nodes = root.SelectNodes("/GlobalChangeset/DocSetChangeset");
+
+ // IMO it's best to generate different Mails for
+ // different DocSets, so the correct people can get their hands on it.
+ // e.g one mail for Gtk#, one for ecma docs.
+
+ foreach (XmlNode node in nodes) {
+
+ string datastring = "";
+
+ XmlNodeList filenodes = node.SelectNodes("FileChangeset");
+
+
+ foreach (XmlNode filenode in filenodes) {
+ datastring += RenderFileSet(filenode);
+ }
+
+ string target = node.Attributes["DocSet"].Value;
+
+ string header = "---------------------\n"
+ + "MonoDoc Change\n"
+ + "---------------------\n\n"
+ + "This mail was generated by monodoc.\n\n"
+ + "--------------------------------------------------\n"
+ + "Author: " + author + "\n"
+ + "EMail: " + email + "\n"
+ + "personal Message: " + personalmessage + "\n\n"
+ + "--------------------------------------------------\n\n"
+ + "Changes are listed below:\n\n"
+ + "*************************************\n\n";
+
+ string footer = "\n\n---------------------------------------\n"
+ + "Monodoc Editing WebService";
+
+ SendMail("Monodoc: " + target, header + datastring + footer);
+ }
+
+ }
+
+ catch {
+
+ response = new Response();
+ response.Status = 5;
+ response.Message = "An unknown error occured.";
+
+ return response;
+
+ }
+
+
+ XmlNode rootnode = dataroot.SelectSingleNode("/oldposts");
+
+ XmlElement newentry = oldposts.CreateElement("post");
+ newentry.SetAttribute("md5", newsum);
+ newentry.SetAttribute("date", today);
+ rootnode.AppendChild(newentry);
+ oldposts.Save("oldposts.xml");
+
+ response = new Response();
+ response.Status = 1;
+ response.Message = "Your changes were sent to Mono Docs List.\n"
+ + "They will be reviewed as soon as possible.";
+
+ return response;
+
+ }
+
+ string RenderFileSet(XmlNode filenode) {
+
+ // Rendering should be improved eventually,
+ // so no xml remains.
+
+ return "FILE: " + filenode.Attributes["RealFile"] + "\n\n"
+ + filenode.InnerXml
+ + "\n\n*************************************\n\n";
+ }
+
+ public class Response {
+
+ public int Status;
+ public string Message;
+ }
+
+ public void SendMail(string subject, string body) {
+
+ System.Web.Mail.MailMessage mailMessage = new System.Web.Mail.MailMessage();
+
+ // NOTE: I have made this "groith@tcrz.net",
+ // so it won't be blocked.
+ // Should be changed later.
+
+ mailMessage.From = "groith@tcrz.net";
+ mailMessage.To = "mono-docs-list@ximian.com";
+ mailMessage.Subject = subject;
+ mailMessage.Body = body;
+ mailMessage.BodyFormat = System.Web.Mail.MailFormat.Text;
+
+ System.Web.Mail.SmtpMail.SmtpServer = "post.tcrz.net";
+ System.Web.Mail.SmtpMail.Send(mailMessage);
+
+
+ }
+
+ // from http://weblog.stevex.org/radio/stories/2002/12/08/
+ // cCodeSnippetCreatingAnMd5HashString.html
+
+ public string GetMd5Sum(string str)
+ {
+ Encoder enc = System.Text.Encoding.Unicode.GetEncoder();
+
+ byte[] unicodeText = new byte[str.Length * 2];
+ enc.GetBytes(str.ToCharArray(), 0, str.Length, unicodeText, 0, true);
+
+ MD5 md5 = new MD5CryptoServiceProvider();
+ byte[] result = md5.ComputeHash(unicodeText);
+
+ StringBuilder sb = new StringBuilder();
+ for (int i=0;i<result.Length;i++)
+ {
+ sb.Append(result[i].ToString("X2"));
+ }
+
+ return sb.ToString();
+}
+
+
+}
diff --git a/webdoc/plugins/contributor-plugin/server.asmx b/webdoc/plugins/contributor-plugin/server.asmx
new file mode 100644
index 00000000..1967a4ba
--- /dev/null
+++ b/webdoc/plugins/contributor-plugin/server.asmx
@@ -0,0 +1 @@
+<%@ WebService Language="c#" Codebehind="server.cs" Class="Monodoc.Contributions" %>
diff --git a/webdoc/plugins/contributor-plugin/server.cs b/webdoc/plugins/contributor-plugin/server.cs
new file mode 100644
index 00000000..d026cb22
--- /dev/null
+++ b/webdoc/plugins/contributor-plugin/server.cs
@@ -0,0 +1,366 @@
+//
+// Monodoc server
+//
+// Author:
+// Miguel de Icaza (miguel@ximian.com)
+//
+
+using System;
+using System.Collections;
+using System.IO;
+using System.Web.Mail;
+using System.Web.Services;
+using System.Web.Services.Protocols;
+using System.Data;
+using ByteFX.Data.MySqlClient;
+using System.Xml;
+
+namespace Monodoc {
+ [WebServiceAttribute (Description="Web service for the MonoDoc contribution system")]
+ public class Contributions : System.Web.Services.WebService
+ {
+ const string basedir = "/home/contributions/";
+ //const string basedir = "/tmp/contributions/";
+ static string connection_string;
+
+ static Contributions ()
+ {
+ using (StreamReader sr = new StreamReader (File.OpenRead ("connection.string"))){
+ connection_string = sr.ReadLine ();
+ Console.WriteLine ("Connection: " + connection_string);
+ }
+ }
+
+ private IDbConnection GetConnection()
+ {
+ return new MySqlConnection(connection_string);
+ }
+
+ private MySqlParameter CreateParameter(string name, object value)
+ {
+ return new MySqlParameter (name, value);
+ }
+
+ static void mail (string recipient, string body)
+ {
+ MailMessage m = new MailMessage ();
+ m.From = "mono-docs-list@ximian.com";
+ m.To = recipient;
+ m.Subject = "Your Monodoc passkey";
+ m.Body = String.Format ("\n\nWelcome to the Mono Documentation Effort,\n\n" +
+ "This is your passkey for contributing to the Mono Documentation effort:\n " +
+ " {0}\n\n" +
+ "The Mono Documentation Team (mono-docs-list@ximian.com)", body);
+
+ SmtpMail.SmtpServer = "localhost";
+ SmtpMail.Send (m);
+ }
+
+ //
+ // 0 => OK to send contributions.
+ // -1 => Invalid version
+ //
+ [WebMethod(Description="Check the client/server version; 0 means that the server can consume your data")]
+ public int CheckVersion (int version)
+ {
+ if (version == 1)
+ return 0;
+ return -1;
+ }
+
+ //
+ // Return codes:
+ // -3 invalid characters in login
+ // -2 Login already registered, password resent.
+ // -1 Generic error
+ // 0 password mailed
+ //
+ [WebMethod(Description="Requests a registration for a login")]
+ public int Register (string login)
+ {
+ if (login.IndexOf ("'") != -1)
+ return -3;
+
+ IDbConnection conn = GetConnection();
+ conn.Open();
+ try
+ {
+ IDbCommand cmd = conn.CreateCommand();
+ cmd.CommandText = "select password from person where name=@login";
+ cmd.Parameters.Add( CreateParameter("@login", login));
+ IDataReader reader = cmd.ExecuteReader ();
+
+ if (reader.Read ()){
+ string password = (string) reader ["password"];
+ mail (login, password);
+ reader.Close ();
+ return -2;
+ }
+ reader.Close ();
+ Random rnd = new Random ();
+ int pass = rnd.Next ();
+ cmd.CommandText = "INSERT INTO person (name, password, last_serial) VALUES " +
+ "(@name, @password, 0)";
+ cmd.Parameters.Add( CreateParameter("@name",login));
+ cmd.Parameters.Add( CreateParameter("@password",pass));
+
+ cmd.ExecuteNonQuery ();
+ mail (login, pass.ToString ());
+
+ return 0;
+ } catch (Exception e) {
+ Console.Error.WriteLine (e);
+ } finally {
+ conn.Close ();
+ }
+ return -1;
+ }
+
+ [WebMethod (Description="Returns the latest serial number used for a change on the server")]
+ public int GetSerial (string login, string password)
+ {
+ IDbConnection conn = GetConnection();
+ conn.Open();
+ try
+ {
+ IDbCommand cmd = conn.CreateCommand();
+ cmd.CommandText = "select last_serial from person where name=@login and password=@password";
+ cmd.Parameters.Add( CreateParameter("@login", login));
+ cmd.Parameters.Add( CreateParameter("@password", password));
+
+ object r = cmd.ExecuteScalar();
+ if (r != null){
+ Console.Error.WriteLine (r);
+ return (int) r;
+ }
+ return -1;
+ } catch (Exception e){
+ Console.Error.WriteLine ("Exception" + e);
+ } finally {
+ conn.Close();
+ }
+ return -1;
+ }
+
+ // -1 Generic error.
+ // -2 Erroneous XML
+ int a=1;
+ [WebMethod (Description="Submits a GlobalChangeSet as a contribution")]
+ public int Submit (string login, string password, XmlNode node)
+ {
+ IDbConnection conn = GetConnection();
+ conn.Open();
+ try {
+ IDbCommand cmd = conn.CreateCommand();
+ cmd.CommandText = "select * from person where name=@login and password=@password";
+ cmd.Parameters.Add( CreateParameter("@login", login));
+ cmd.Parameters.Add( CreateParameter("@password", password));
+
+ IDataReader reader = cmd.ExecuteReader ();
+
+ int ret_val = -1;
+
+ if (reader.Read()){
+ int id = (int)reader["person_id"];
+ int serial = (int)reader["last_serial"];
+ reader.Close ();
+
+ //
+ // Validate the XML
+ //
+ XmlDocument d = new XmlDocument ();
+ d.AppendChild (d.ImportNode (node, true));
+ XmlNodeReader r = new XmlNodeReader (d);
+ try {
+ object rr = GlobalChangeset.serializer.Deserialize (r);
+ } catch {
+ return -2;
+ }
+
+ string dudebase = basedir + id;
+ Directory.CreateDirectory (dudebase);
+
+ d.Save (dudebase + "/" + serial + ".xml");
+ IDbTransaction txn = conn.BeginTransaction();
+ try {
+ cmd.CommandText = "UPDATE person SET last_serial=@last_serial WHERE name=@name AND password=@pwd";
+ cmd.Parameters.Add( CreateParameter("@last_serial", serial+1));
+ cmd.Parameters.Add( CreateParameter("@name", login));
+ cmd.Parameters.Add( CreateParameter("@pwd", password));
+ cmd.ExecuteNonQuery ();
+
+
+ cmd.CommandText = "INSERT INTO status (person_id, serial, status) VALUES (@id, @serial, 0)";
+ cmd.Parameters.Add( CreateParameter("@id",id));
+ cmd.Parameters.Add( CreateParameter("@serial",serial));
+ cmd.ExecuteNonQuery ();
+
+ txn.Commit();
+ } catch (Exception e) {
+ Console.Error.WriteLine ("E: " + e);
+ }
+
+ ret_val = serial+1;
+ return ret_val;
+ }
+ Console.Error.WriteLine ("Error, going: 4");
+ return -4;
+ } catch (Exception e) {
+ Console.Error.WriteLine ("Failure in Submit: " + e);
+ return -3;
+ } finally {
+ conn.Close ();
+ }
+ }
+
+ bool IsAdmin (IDbConnection conn, string login, string password)
+ {
+ IDbCommand cmd = conn.CreateCommand();
+ cmd.CommandText = "select person_id,is_admin from person where name=@name and password=@pass";
+ cmd.Parameters.Add( CreateParameter("@name",login));
+ cmd.Parameters.Add( CreateParameter("@pass",password));
+
+ int person_id = -1;
+ bool is_admin = false;
+ using (IDataReader reader = cmd.ExecuteReader ()){
+ if (reader.Read ()){
+ person_id = (int) reader ["person_id"];
+ is_admin = ((int) reader ["is_admin"]) == 1;
+ } else
+ return false;
+ }
+ if (person_id == -1 || is_admin == false)
+ return false;
+
+ return true;
+ }
+
+ [WebMethod (Description="Obtains the list of pending contributions")]
+ public PendingChange [] GetPendingChanges (string login, string password)
+ {
+ IDbConnection conn = GetConnection();
+ conn.Open ();
+
+ try {
+ if (!IsAdmin (conn, login, password)){
+ return new PendingChange [0];
+ }
+
+ IDbCommand cmd = conn.CreateCommand();
+ ArrayList results = new ArrayList ();
+ cmd.CommandText = "select status.person_id, serial, person.name from status, person where status=0 and person.person_id = status.person_id";
+ using (IDataReader reader = cmd.ExecuteReader ()){
+ while (reader.Read ()){
+ results.Add (new PendingChange ((string) reader ["name"], (int) reader ["person_id"], (int) reader ["serial"]));
+ }
+ }
+
+ PendingChange [] ret = new PendingChange [results.Count];
+ results.CopyTo (ret);
+ return ret;
+ } catch (Exception e){
+ Console.Error.WriteLine (e);
+ return null;
+ } finally {
+ conn.Close ();
+ }
+ }
+
+ [WebMethod (Description="Obtains a change set for a user")]
+ public XmlNode FetchContribution (string login, string password, int person_id, int serial)
+ {
+ IDbConnection conn = GetConnection ();
+ conn.Open ();
+ try {
+ if (!IsAdmin (conn, login, password))
+ return null;
+
+ XmlDocument d = new XmlDocument ();
+ string fname = basedir + person_id + "/" + serial + ".xml";
+ d.Load (fname);
+ return d.FirstChild;
+ } finally {
+ conn.Close ();
+ }
+ }
+
+ [WebMethod (Description="ADMIN: Obtains the number of pending commits")]
+ public Status GetStatus (string login, string password)
+ {
+ IDbConnection conn = GetConnection ();
+ conn.Open ();
+ try {
+ IDbCommand cmd = conn.CreateCommand();
+ cmd.CommandText = "select * from person where name=@name and password=@pass";
+ cmd.Parameters.Add( CreateParameter("@name",login));
+ cmd.Parameters.Add( CreateParameter("@pass",password));
+
+ IDataReader reader = cmd.ExecuteReader ();
+ int id = -1;
+
+ if (reader.Read())
+ id = (int)reader["person_id"];
+ reader.Close ();
+ if (id == -1)
+ return null;
+
+ Status s = new Status ();
+
+ cmd.CommandText = String.Format ("select count(*) from status where person_id='{0}'", id);
+ s.Contributions = (int) cmd.ExecuteScalar ();
+ cmd.CommandText = String.Format ("select count(*) from status where person_id='{0}' and status='0'", id);
+ s.Pending = (int) cmd.ExecuteScalar ();
+ cmd.CommandText = String.Format ("select count(*) from status where person_id='{0}' and status='1'", id);
+ s.Commited = (int) cmd.ExecuteScalar ();
+
+ return s;
+ } finally {
+ conn.Close ();
+ }
+ }
+
+ [WebMethod (Description="ADMIN: Updates the status of a contribution")]
+ public void UpdateStatus (string login, string password, int person_id, int contrib_id, int status)
+ {
+ IDbConnection conn = GetConnection();
+ conn.Open ();
+
+ try {
+ if (!IsAdmin (conn, login, password))
+ return;
+
+ IDbCommand cmd = conn.CreateCommand();
+ cmd.CommandText = "update status set status=@status WHERE person_id=@PID AND serial=@ser";
+ cmd.Parameters.Add (CreateParameter ("@status", status));
+ cmd.Parameters.Add (CreateParameter ("@PID", person_id));
+ cmd.Parameters.Add (CreateParameter ("@ser", contrib_id));
+ cmd.ExecuteNonQuery ();
+ } finally {
+ conn.Close ();
+ }
+ }
+ }
+
+ public class Status {
+ public int Contributions;
+ public int Commited;
+ public int Pending;
+ }
+
+ public class PendingChange {
+ public string Login;
+ public int ID;
+ public int Serial;
+
+ public PendingChange (string login, int person_id, int serial)
+ {
+ Login = login;
+ ID = person_id;
+ Serial = serial;
+ }
+
+ public PendingChange ()
+ {
+ }
+ }
+}
diff --git a/webdoc/plugins/contributor-plugin/tables.sql b/webdoc/plugins/contributor-plugin/tables.sql
new file mode 100644
index 00000000..2e951946
--- /dev/null
+++ b/webdoc/plugins/contributor-plugin/tables.sql
@@ -0,0 +1,21 @@
+use monodoc;
+drop table person;
+drop table status;
+create table person (
+ name varchar (80) not null,
+ password varchar (20) not null,
+ person_id int not null primary key auto_increment,
+ last_serial int not null,
+ last_update int not null,
+ is_admin int not null
+);
+
+create table status (
+ person_id int not null,
+ serial int not null,
+ status int not null
+);
+
+insert into person (name, password, last_serial, is_admin) values ('miguel@ximian.com', 'login1', 0, 1);
+insert into person (name, password, last_serial) values ('nat@nat.org', 'login2', 0);
+
diff --git a/webdoc/plugins/contributor-plugin/wiki2ecmahelper.xsl b/webdoc/plugins/contributor-plugin/wiki2ecmahelper.xsl
new file mode 100644
index 00000000..4039cd9e
--- /dev/null
+++ b/webdoc/plugins/contributor-plugin/wiki2ecmahelper.xsl
@@ -0,0 +1,70 @@
+<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
+
+ <!-- default rule -->
+ <xsl:template match="*">
+ <xsl:copy>
+ <xsl:copy-of select="@*" />
+ <xsl:apply-templates />
+ </xsl:copy>
+ </xsl:template>
+
+ <xsl:template match="code">
+ <xsl:element name="c"><xsl:apply-templates /></xsl:element>
+ </xsl:template>
+
+ <xsl:template match="div">
+ <xsl:choose>
+ <xsl:when test="@class = 'example'">
+ <example><xsl:apply-templates /></example>
+ </xsl:when>
+ <xsl:when test="@class = 'behavior'">
+ <block type="behavior"><xsl:apply-templates /></block>
+ </xsl:when>
+ <xsl:when test="@class = 'default'">
+ <block type="default"><xsl:apply-templates /></block>
+ </xsl:when>
+ <xsl:when test="@class = 'example-block'">
+ <block type="example"><xsl:apply-templates /></block>
+ </xsl:when>
+ <xsl:when test="@class = 'overrides'">
+ <block type="overrides"><xsl:apply-templates /></block>
+ </xsl:when>
+ <xsl:when test="@class = 'usage'">
+ <block type="usage"><xsl:apply-templates /></block>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:copy-of select="." />
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:template>
+
+ <xsl:template match="table">
+ <list type="table">
+ <xsl:if test="tr[1]/th">
+ <listheader><item>
+ <term>
+ <xsl:apply-templates select="tr[1]/th[1]" />
+ </term>
+ <xsl:for-each select="tr[1]/th[position() > 1]">
+ <description>
+ <xsl:apply-templates />
+ </description>
+ </xsl:for-each>
+ </item></listheader>
+ </xsl:if>
+ <xsl:for-each select="tr">
+ <item>
+ <term>
+ <xsl:apply-templates select="td[1]" />
+ </term>
+ <xsl:for-each select="td[position() > 1]">
+ <description>
+ <xsl:apply-templates />
+ </description>
+ </xsl:for-each>
+ </item>
+ </xsl:for-each>
+ </list>
+ </xsl:template>
+
+</xsl:transform>