Archive

Author Archive

My Documents Web Part Now Supports Multiple File Upload

June 7th, 2010 Richard No comments

I’ve just added support for uploading multiple files to the My Documents and My Shared Documents web parts. It’s a pretty simple implementation – if you click on Upload Multiple Documents

uploadMultipleClosed

then you get given the option to upload up to 5 documents at a time.

uploadMultipleOpen

Nice and simple.

If you are looking to upload more documents than that, then really you probably ought to be using SharePoint itself as the document repository. I always look on these web parts as a step on the way to fully using SharePoint, not as a long-term solution.

However, if you really need to upload many files, just zip them up, upload and unpack them when you are next in school/work.

Categories: My Documents Tags:

Creating Parent Accounts for your VLE from Sims, Facility CMIS or other MIS

June 7th, 2010 Richard No comments

A question which comes up frequently is how shall we create parent accounts for our VLE or parental engagement system? This discussion is relevant whichever VLE / parental engagement system you are using and whatever your MIS.

There’s 2 main ways of creating parental access accounts:

  1. Create one parental access account per student in the MIS.
  2. Create an account per contact in the MIS who has parental responsibility for a student.
    When schools first start thinking about parental access, then the one parental access account per student is usually the first one which springs to mind. This is certainly the easiest way to initially manage the accounts : you can just take an extract of students from your system and use a similar way of creating the parental accounts as you create your student accounts.

Option 2 initially is harder, because to be blunt, the quality of the contact information in any MIS is generally pretty bad. This ranges from missing information which needs be used in creating the account name, to parents being in the system multiple times.

The reasons for this include:

  1. Quirks in the MIS front end make it easier to create new contacts than to find ones linked to siblings and linking them to the current record.
  2. Insufficient information in CTF imports to find and link existing contacts.
  3. Lack of staff training to find and link exisiting contacts.
  4. Until you want to create parental accounts you don’t actually need to collect all the information i.e. Mr Willis is good enough to address letters home with, but not enough information to create uniquely named accounts with.
    Hence, before you can begin creating accounts for individual contacts you need to clean your contact information.

So a parental access account per student initially looks very appealing. However, there are several immediate problems with it:

  1. Sharing an account between multiple people is just plain wrong. For starters there is no auditing. If the application is purely read-only you might accept this, but if there’s any write back/updating from the account, even something as simple as messaging to the teachers, then this is unacceptable. Imagine what could be done in an acrimonious split in the name of the other party. There probably isn’t any system which is purely read-only, even the ones with just read-only access to information can probably set their display name or has a messaging system.
  2. If a parent has multiple children at the school, they will need to login multiple times to see all their children. This is adding extra barriers to use by the parents. We need to make it as easy for them as possible if we want them to engage with the school.
  3. Separated couples cannot be allowed to share an account. If they do they may accidentally or maliciously get access to information they should not have. Again in a purely read-only system, if such a beast exists, you might get away with it.
  4. If a couple split up and one loses parental responsibility, you will need to revoke the account and issue a new one for the parent who still has parental responsibility. Rather than just revoke the one account.

Point 4 gives rise to an further important consideration. Your parental accounts need constant maintenance, you can’t just create them once and forget about them. You need to monitor the contacts to see if anyone has had their parental access removed or has had a court order raised against them. This needs to be done automatically or pro-actively and not just when someone mentions it to you. Their rights to see the student’s information needs to get removed immediately.

So in my opinion you need to create an account per parental contact in your MIS from the get go.

Once you have created your accounts what do you do with them? Well presumably the SLT has a vision for what they are going to be used for or there’s really no point going down this road. As part of this vision they should have considered about how to distribute the credentials. You could just send them home in a letter, but that’s insecure and not really engaging the parents with what they can do with them. The best ideas that I have seen about this is inviting the parents and their children to sessions at the school where the school explains what they are trying to achieve, how the parents and pupils can best make use of this information and does a quick training session on how to use the parental engagement tools. They are then given their credentials at the session and should know pretty much exactly what they can do and how they can engage with the school.

BETT 2010

January 12th, 2010 Richard 1 comment

 

It’s that time of year again when Olympia opens its doors to the world of IT in Education and BETT begins. I’ll be there on Wednesday, Thursday and Friday and would love to meet as many of your as possible, whether you are customers, SLK users or just vaguely interested in what we do. Again I’ll be spending most of my time looking at the stands, so if you want to meet we can either arrange a date and time or you can just give me a call when you are free – although judging from past years it’s not always possible to hear my phone at BETT. Failing that, I’ll probably spend some time at the LP+ stand (E46 in the Main Hall), currently I’m planning to be there 1400-1445 every day. I also expect I’ll be hanging around the Microsoft stand as well as I know quite a few of the guys on there.

Categories: Uncategorized Tags:

SharePoint Learning Kit 1.4 Released

January 11th, 2010 Richard 8 comments

I’ve finally released SLK 1.4 to Beta. Sorry about the delay, but in the end I’ve rewritten the drop box functionality to hopefully work seamlessly within SharePoint. To do this I knew I needed to make changes to how the drop box library was created which would be incompatible and so decided to hold back on officially releasing it.

You can download from the release page on CodePlex.

It is not backwards compatible with the version uploaded to the patches folder, so any documents returned by that will not be available via this version. The documents will still be present though.

The major changes compared to the version in the patches folder are:

  1. Students can open office documents and save them straight back to SharePoint without having to save to disk first.
  2. Teachers can open and comment on office documents without having to save to disk first.
  3. The drop box library is created as required. You do not have to enable the SLK feature on the site to create it.
  4. Although folders are still used as containers to hold student’s work (as the document names are likely to be the same), they are not used to navigate the assignments. You either use the default view which is grouped by assignment or use assignment specific views which are created when an assignment is created.
  5. You can use the drop box in a locale which doesn’t use US style dates.
  6. I’ve currently removed the download all and upload all files options for teachers so that I can get the release out. I just haven’t had time to complete this.
  7. I’ve removed Course Manager from the install. This will again be available as a separate release. The reason is that the quality is still not there for it to be bundled.

I will consider this version to be in beta until 24 Jan at the latest. At which point there will be another beta version with at a minimum the download all and upload all functionality in, or a final release. Please download and report any bugs, which I will attempt to resolve quickly. I am keen to get 1.4 RTM so we can move on to the next version and get the project moving again.

Note, I still need to update the documentation to cover this release, this may take some time. If anyone would like to volunteer to do this it would be really helpful. I’m also considering moving it to the wiki pages on CodePlex rather than just having the getting started pdf as it will be easier to maintain and distribute. Does anyone have any thoughts on this?

Categories: SLK Tags: ,

Salamander DataViewer now supports IWebPartField connections

November 11th, 2009 Richard No comments

I’ve just updated the Salamander DataViewer web part to support connections to other web parts which provide an IWebPartField connection.

I’ve also updated the User Search and My Children web parts, part of our MIS Web Parts solution, to provide an IWebPartField connection. Here’s a screen shot of a simple connection where My Children is linked to the DataViewer.

DataViewerIWebPartFieldConnection

This is likely going to be most useful for linking to external systems holding information about your pupils and staff.

Categories: Data Viewer Tags:

Setting the Owner of Files and Directories in C#

October 21st, 2009 Richard No comments

I recently had a requirement to set the owners of users home directories on a Windows server. The .Net framework has built-in support for this so it simply looked like a case of doing this:

IdentityReference owner = new NTAccount("MYDOMAIN\\MyUser");
DirectoryInfo directory = new DirectoryInfo("c:\\myDirectory");
DirectorySecurity directorySecurity = directory.GetAccessControl();
directorySecurity.SetOwner(owner);
directory.SetAccessControl(directorySecurity);

However, when I tried this I just got an InvalidOperationException with the message "The security identifier is not allowed to be the owner of this object".

It turns out that the reason for this is that normally you are only allowed to take ownership yourself, and not assign it. For a user to take ownership they must either have been given the Take Ownership permission or be an administrator.

There is one exception to this rule, and that is if the user has the Restore files and directories privilege then they can assign ownership to other users. Now administrators have this privilege, but by default it is disabled. More details on this from Microsoft.

So to set the owner of the file, you need to have the Restore Files and Directories privilege and then enable it before setting the owner. Really we should also disable the privilege when we’ve finished using it as well.

Unfortunately .Net doesn’t have built in support for this yet, so we are reduced to PInvoking native methods and here’s the code:

sealed class UnmanagedCode
{
    [DllImport("kernel32.dll", SetLastError=true)]
    [return: MarshalAs(UnmanagedType.Bool)]
    static extern bool CloseHandle(IntPtr hObject);

    // Use this signature if you do not want the previous state
    [DllImport("advapi32.dll", SetLastError=true)]
    [return: MarshalAs(UnmanagedType.Bool)]
    static extern bool AdjustTokenPrivileges(IntPtr tokenHandle,
        [MarshalAs(UnmanagedType.Bool)]bool disableAllPrivileges,
        ref TOKEN_PRIVILEGES newState,
        UInt32 bufferLength,
        IntPtr previousState,
        IntPtr returnLength);

    [DllImport("kernel32.dll", ExactSpelling = true)]
    static extern IntPtr GetCurrentProcess();

    [DllImport("advapi32.dll", ExactSpelling = true, SetLastError = true)]
    static extern bool OpenProcessToken
        (IntPtr processHandle, int desiredAccess, ref IntPtr phtok);

    [DllImport("advapi32.dll", SetLastError = true)]
    static extern bool LookupPrivilegeValue
            (string host, string name, ref LUID lpLuid);

    [StructLayout(LayoutKind.Sequential, Pack = 1)]
    struct TOKEN_PRIVILEGES
    {
        public UInt32 PrivilegeCount;
        public LUID Luid;
        public UInt32 Attributes;
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct LUID
    {
       public uint LowPart;
       public int HighPart;
    }

    const int SE_PRIVILEGE_ENABLED = 0x00000002;
    const int TOKEN_QUERY = 0x00000008;
    const int TOKEN_ADJUST_PRIVILEGES = 0x00000020;
    //http://msdn.microsoft.com/en-us/library/bb530716(VS.85).aspx
    const string SE_RESTORE_PRIVILEGE = "SeRestorePrivilege"; 

    public static void GiveRestorePrivilege()
    {
        TOKEN_PRIVILEGES tokenPrivileges;
        tokenPrivileges.PrivilegeCount = 1;
        tokenPrivileges.Luid = new LUID();
        tokenPrivileges.Attributes = SE_PRIVILEGE_ENABLED;

        IntPtr tokenHandle = RetrieveProcessToken();

        try
        {
            bool success = LookupPrivilegeValue
                        (null, SE_RESTORE_PRIVILEGE, ref tokenPrivileges.Luid);
            if (success == false)
            {
                int lastError = Marshal.GetLastWin32Error();
                throw new Exception(
                    string.Format("Could not find privilege {0}. Error {1}",
                                        SE_RESTORE_PRIVILEGE, lastError));
            }

            success = AdjustTokenPrivileges(
                                                tokenHandle, false,
                                                ref tokenPrivileges, 0,
                                                IntPtr.Zero, IntPtr.Zero);
            if (success == false)
            {
                int lastError = Marshal.GetLastWin32Error();
                throw new Exception(
                    string.Format("Could not assign privilege {0}. Error {1}",
                                    SE_RESTORE_PRIVILEGE, lastError));
            }
        }
        finally
        {
            CloseHandle(tokenHandle);
        }

    }

    static IntPtr RetrieveProcessToken()
    {
        IntPtr processHandle = GetCurrentProcess();
        IntPtr tokenHandle = IntPtr.Zero;
        bool success = OpenProcessToken(processHandle,
                                        TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
                                        ref tokenHandle);
        if (success == false)
        {
            int lastError = Marshal.GetLastWin32Error();
            throw new Exception(
                string.Format("Could not retrieve process token. Error {0}",
                                    lastError));
        }
        return tokenHandle;
    }
}

To remove the privilege you will just need to replace SE_PRIVILEGE_ENABLED with the disabled value. In my use I’m just setting the owner and finishing the process so it’s not really required.

Categories: Development Tags:

How to Mock HttpWebRequest when Unit Testing

October 18th, 2009 Richard 5 comments

One of our latest products interacts with a Restful web service. As this is the core part of its functionality as part of Test Driven Development and Unit Testing I needed to be able to test the calls to the web service using HttpWebRequest.

A quick Google didn’t come up with anything so I started looking at the best way to mock the calls. My initial thought was to extract all use of HttpWebRequest into a separate class, define an interface for setting the request and getting the response and use Dependency Injection to determine whether to use the ‘normal’ class or a mock.

Then I looked a bit closer at WebRequest.Create which is the method you use to create a HttpWebRequest. I noticed that it uses a Factory Method so you could actually register your own factory object depending on the url used. So without any extra code required in the class under test, you can register your factory object and the .Net Framework will automatically use your mocks or stubs. This is pretty cool.

To take advantage of this you need to implement the IWebRequestCreate interface on your factory object, and then register your factory object with WebRequest.RegisterPrefix. What you do in the Create method is up to you, but I created a simple WebRequest and WebResponse pair which store the request for you to test the input, and which returns a configurable response.

First an example of how you can use these:

string response = "my response string here";
WebRequest.RegisterPrefix("test", new TestWebRequestCreate());
TestWebRequest request = TestWebRequestCreate.CreateTestRequest(response);

string url = "test://MyUrl";

ObjectUnderTest myObject = new ObjectUnderTest();
myObject.Url = url;
// DoStuff call the url with a request and then processes the
// response as set above
myObject.DoStuff();

string requestContent = request.ContentAsString();
Assert.AreEqual(expectedRequestContent, requestContent);

The code for these 3 objects is:

/// <summary>A web request creator for unit testing.</summary>
class TestWebRequestCreate : IWebRequestCreate
{
    static WebRequest nextRequest;
    static object lockObject = new object();

    static public WebRequest NextRequest
    {
        get { return nextRequest ;}
        set
        {
            lock (lockObject)
            {
                nextRequest = value;
            }
        }
    }

    /// <summary>See <see cref="IWebRequestCreate.Create"/>.</summary>
    public WebRequest Create(Uri uri)
    {
        return nextRequest;
    }

    /// <summary>Utility method for creating a TestWebRequest and setting
    /// it to be the next WebRequest to use.</summary>
    /// <param name="response">The response the TestWebRequest will return.</param>
    public static TestWebRequest CreateTestRequest(string response)
    {
        TestWebRequest request = new TestWebRequest(response);
        NextRequest = request;
        return request;
    }
}

class TestWebRequest : WebRequest
{
    MemoryStream requestStream = new MemoryStream();
    MemoryStream responseStream;

    public override string Method { get; set; }
    public override string ContentType { get; set; }
    public override long ContentLength { get; set; }

    /// <summary>Initializes a new instance of <see cref="TestWebRequest"/>
    /// with the response to return.</summary>
    public TestWebRequest(string response)
    {
        responseStream = new MemoryStream(System.Text.Encoding.UTF8.GetBytes(response));
    }

    /// <summary>Returns the request contents as a string.</summary>
    public string ContentAsString()
    {
        return System.Text.Encoding.UTF8.GetString(requestStream.ToArray());
    }

    /// <summary>See <see cref="WebRequest.GetRequestStream"/>.</summary>
    public override Stream GetRequestStream()
    {
        return requestStream;
    }

    /// <summary>See <see cref="WebRequest.GetResponse"/>.</summary>
    public override WebResponse GetResponse()
    {
        return new TestWebReponse(responseStream);
    }
}

class TestWebReponse : WebResponse
{
    Stream responseStream;

    /// <summary>Initializes a new instance of <see cref="TestWebReponse"/>
    /// with the response stream to return.</summary>
    public TestWebReponse(Stream responseStream)
    {
        this.responseStream = responseStream;
    }

    /// <summary>See <see cref="WebResponse.GetResponseStream"/>.</summary>
    public override Stream GetResponseStream()
    {
        return responseStream;
    }
}

This is quite a simple implementation, just to check the request and return a known response. Once you’ve got this working, you can obviously do more tests such as simulating error conditions.

Categories: Development, Unit Testing Tags:

New Product – Salamander MoodleRooms

October 18th, 2009 Richard No comments

I’m pleased to announce that we’ve got a new product in our line-up, Salamander MoodleRooms. This allows integration between School Management Systems and the MoodleRooms hosted Moodle solution.

So whether you are using Sims, Facility CMIS, Integris, Phoenix or any of the other main systems, we can now automatically maintain users and courses in your hosted Moodle as they change in your MIS.

On a technical level, we using MoodleRooms’ system integration tool (UIB) over https to send the changes up to MoodleRooms.

Categories: Uncategorized Tags:

FTP in Vista using Network Location in Windows

September 25th, 2009 Richard No comments

I often ftp files up to our web server so I can access them while on client machines. Up until now I’ve been using FireFtp a Firefox extension, which works great as an FTP client. However, I’d been getting annoyed by it for 2 reasons:

  1. Not being able to use keyboard shortcuts as it was hosted in a browser
  2. Not being able to use the Favourite links set up in explorer. About 90% of what I upload would be available in one-click from there.

So I started looking for an alternative client. What if found was even better. You can add a network location in Windows Explorer which is an ftp location and can then drag and drop files completely within Explorer.

To set it up all you need to do is select Computer in the folder view, then right click in the details pane and select "Add Network Location" and follow the wizard.

I imagine it’s present in other versions of Windows, but I’ve only tested it in Vista.

Categories: Uncategorized Tags:

My Documents Now Setting Owner Properly

September 5th, 2009 Richard No comments

While debugging the issue in my last post, the customer pointed out the the owner of uploaded documents and created folders wasn’t being set as expected i.e. as the user logged SharePoint.

This was the result of overcoming the double-hop problem – one option is to access the file system as the SharePoint app pool, or the user defined in a configuration file. In these cases, it was this user who was set as the owner of the object. I’ve now fixed this so the owner will be the user logged into SharePoint.

Categories: Uncategorized Tags: