Friday, December 25, 2009

Camlex.NET project announce

Recently we tried Caml.NET in our project. Since it is obviously step forward in caml queries creation, it has its own disadvantages. Vladimir Timashkov recently made a post in his blog where he summarized some issues of Sharepoint. One of them  is about SPQuery creation – it has no friendly development interface currently. So in order to improve this situation we decided to implement an alternative way to create SPQueries – via lambda expressions. The new project name is Camlex.NET (caml via expressions). It is located in http://camlex.codeplex.com (not published yet – i.e. visible only for contributors).

Me and Vladimir are coordinators of the project. In the further posts I will notify about project status.

Monday, December 21, 2009

Pass locale of current web site (SPWeb) in Sharepoint into javascript

Technique described below can be actually used for regular ASP.Net applications when you need to pass some server variable into javascript code – i.e. in general it is not Sharepoint-specific. Nevertheless I used it recently to pass locale of current SPWeb into external .js file.

We often use server variables in javascript code when we need to determine ClientID of some server control in javascript code embedded into page:

   1: var txtEmail = document.getElementById("<%= this.txtEmail.ClientID %>")
Unfortunately this approach can’t be used when javascript code is located in external .js file (btw this is recommended approach for web applications development – do not mess layout and javascript code) because .js file is not processed by ASP.Net by default.

The main idea for external .js file is quite simple – use global variable (of course you can use namespaces as well, but in this post I will use global variable for simplicity) which will be available in .js file and which will keep locale of current SPWeb:

   1: <%@ Import Namespace="Microsoft.SharePoint" %>
   2: <script type="text/javascript">
   3:     var globalLocale = "<%= SPContext.Current.Web.Language %>";
   4: </script>

To use this variable in .js file the following function was added:

   1:  
   2: getLocaleOfCurrentSiteOrEmpty = function() {
   3:     var localLocale = "";
   4:     try {
   5:         localLocale = globalLocale;
   6:     }
   7:     catch (e) {
   8:         localLocale = "";
   9:     }
  10:     return localLocale;
  11: }

So those pages which don’t have globalLocale defined will have empty value and then use some default settings.

Keeping in mind DRY principle we didn’t want to copy and past definition of globalLocale variable in each page where it is required. In order to avoid duplication several approaches can be used:

  • include definition of globalLocale variable using server-side include. I.e. you need to move definition into separate .ascx file (extension is not important actually) and then include it in your pages:
       1: <!--#include virtual="GlobalLocale.ascx"-->
    This appoach works only for application pages – i.e. pages which are stored on filesystem in 12/template/layouts folder. It doesn’t work for publishing pages and master pages because server-side includes are not allowed in pages of this type.
  • use regular user control .ascx file, which contains definition of globalLocale variable, and register it as regular user control wherever you need. This approach works both for application and publishing pages.

We used 2nd approach – but if you are not able to use user controls because of some reasons, 1st way is applicable as well.

Wednesday, December 16, 2009

Use gmail smtp server for post commit notifications in Subversion via mailer.py

In my previous post I described how to enable conditional post commit notifications in Subversion. In this post I’m going to show how to extend mailer.py from subversion tools in order to use gmail smtp server (smtp.gmail.com:587) for sending emails.

You should note one thing if you want to use gmail smtp server for emailing in your applications – it requires SSL enabled. So first you need to create gmail account – its credentials will be used to connect to smtp.gmail.com.  Once gmail account created you need to add new setting “smtp_use_ssl” in mailer.conf file:

   1: [general]
   2:  
   3: smtp_hostname = smtp.gmail.com:587
   4: smtp_username = your_gmail_login
   5: smtp_password = your_gmail_password
   6:  
   7: # 2009-12-13 asadomov: add custom smtp_use_ssl parameter
   8: smtp_use_ssl = true
   9: ...
Next you need to modify SMTPOutput class in mailer.py in order to use added “smtp_use_ssl” setting:
   1: class SMTPOutput(MailedOutput):
   2:   "Deliver a mail message to an MTA using SMTP."
   3:  
   4:   def start(self, group, params):
   5:     MailedOutput.start(self, group, params)
   6:  
   7:     self.buffer = StringIO()
   8:     self.write = self.buffer.write
   9:  
  10:     self.write(self.mail_headers(group, params))
  11:  
  12:   def finish(self):
  13:     server = smtplib.SMTP(self.cfg.general.smtp_hostname)
  14:  
  15:     # 2009-12-13 asadomov: add ssl configuration (e.g. for gmail smtp server)
  16:     if self.cfg.is_set('general.smtp_use_ssl') and self.cfg.general.smtp_use_ssl.lower() == "true":
  17:       server.ehlo()
  18:       server.starttls()
  19:       server.ehlo()
  20:  
  21:     if self.cfg.is_set('general.smtp_username'):
  22:       server.login(self.cfg.general.smtp_username,
  23:                    self.cfg.general.smtp_password)
  24:     server.sendmail(self.from_addr, self.to_addrs, self.buffer.getvalue())
  25:     server.quit()

After that you will be able to use gmail smtp server to send post commit notifications via mailer.py.

Sunday, December 13, 2009

Post commit notifications in Subversion on Windows

Recently I needed to extend svn functionality by adding post commit email notifications for small open source project. The idea was to have some possibility to make commit visible for team members without annoying manual emailing (like “please see commit #123 – I added fluent nhibernate configuration”). We wanted to save our time and have some kind of switch for indicating that this commit is public. Another requirement is that we didn’t want all commits public – we wanted to notify only about those commits which were useful for other team members (of course author of commit decided is it useful or not for other :) ).

In order to implement described behavior I needed to make several things:

  1. Add post commit hook in svn server which sends email notifications
  2. Make it possible to send notifications by some condition. We decided to use ‘!’ symbol as indicator that commit is public. I.e. if contributor adds ‘!’ as first symbols in commit description, then notification should be sent (like “!Fluent nhibernate configuration added")

In order to achieve 1st step I decided to use standard mailer.py script which comes from subversion-tools. There were some drawbacks with installing it on windows. So I will describe the process step by step:

  1. Install python 2.6.x on svn server. On the moment when this post is written it is 2.6.4. Note that currently I didn’t not use 3.x version as I didn’t find python bindings for svn for 3.x versions (see below)
  2. Install python bindings from subversion site . On the moment of installing python bindings I had svn 1.6.6 but binsings was only for 1.6.2. Nevertheless it worked on 1.6.6.
  3. Copy mailer.py and mailer.conf into svn server (I copied it into …\repository\hooks\hook-scripts folder). mailer.conf file can be found on the same page with subversion-tools.
  4. Edit mailer.conf. There are many comments in this file which describe mailer configuration. I needed simple solution with sending mails via smtp. So this is stripped configuration file I used:
  5.    1: [general]
       2: smtp_hostname = your_smtp_server
       3: smtp_username = your_smtp_username
       4: smtp_password = your_smtp_password 
       5:  
       6: [defaults] 
       7:  
       8: diff = /usr/bin/diff -u -L %(label_from)s -L %(label_to)s %(from)s %(to)s 
       9:  
      10: commit_subject_prefix = [SVN-Commit]
      11: propchange_subject_prefix =
      12: lock_subject_prefix =
      13: unlock_subject_prefix = 
      14:  
      15: from_addr = your_from_address
      16: to_addr = your_receiver_1@example.com your_receiver_2@example.com [... your_receiver_n@example.com] 
      17:  
      18: reply_to =
      19: generate_diffs = none
      20: show_nonmatching_paths = yes 
      21:  
      22: [maps]

    Note that it is important to have “generate_diffs = none”. Without it you will need to configure diff tool (via “diff” option)

  6. Create post-commit.cmd script in …\repository\hooks folder:
  7.    1: set REPOS=%1
       2: set REV=%2
       3:  
       4: [your_absolute_path_to_repository]/repository/hooks/hook-scripts/mailer.py commit %REPOS% %REV%

    Note that absolute path is used here

After that recipients (specified in “to_addr” option in mailer.conf) will receive notifications after each commit.

Second step is to make these notifications conditional. It will require slightly change of mailer.py script:

image

After that notifications are sent only if contributor typed ‘!’ symbol in commit description.

Saturday, December 12, 2009

Post login form without submit button in ASP.Net MVC

In web application it is common situation when form should be submitted to server by clicking on Enter key. Recently I needed to add such behavior in ASP.Net MVC application.

There is a login area on top of the master page with 2 textboxes: username and password. These values should be submitted to Login action of LoginController when user press Enter when focus is on one of them:

   1: <%
   2:  using (Html.BeginForm("Login", "Login", FormMethod.Post,
   3: new { name = "loginForm", id = "loginForm"}))
   4:    { 
%>
   5:     <input id="username" name="username" type="text" /><br />
   6:     <input id="password" name="password" type="password" />
   7: <%
   8:  } 
%>

One way I tried – is to add hidden submit button in form and add defaultbutton = "loginButton" attribute to the form:

   1: <input type="submit" id="loginButton" name="loginButton"
   2: style="visibility: hidden" />

But with “visibility: hidden” form was not submitted. When I removed this style everything worked (actually it worked with visible submit button even without defaultbutton = "loginButton" attribute).

Another way which worked for me – is to add keypress handler on textboxes. I added the following jquery script on the page:

   1: <script type="text/javascript">
   2:     $(function() {
   3:         $('#username, #password').keypress(function(e) {
   4:             if (e.which == 13) {
   5:                 $('#loginForm').submit();
   6:             }
   7:         });
   8:     });
   9: </script>

After that form is successfully submited to the server after Enter key press and values are passed to the Login action of the controller.