Home > .Net, C#, Sitecore 6 > Dropbox integration with Sitecore

Dropbox integration with Sitecore

In this post I will make a simple integration from dropbox into the sitecore media library. This is an early release or more a sneak peak at what I hope in time will be a feature rich sitecore open source project/module  “Dropbox integration with Sitecore” With visioning and two sync, and any request that might come in.
So consider this an Alpha-release, I’ve used this Dropbox Context we build in the last blog post “introduction to the dropbox api“. I’ve changend it a little bit so I can be used to make a static .aspx file where you can build the accestoken file. The changend Dropbox context is shown below
 public class DropboxContext
    {
        private OAuthToken _accessToken;

        private string _applicationKey;

        private string _applicationSecret;
        private string _accessTokenPath;

        private OAuthRestClient _apiRestClient;
        private OAuthRestClient _contentiRestClient;

        private string _version = "1.0";

        public DropboxContext(DropBoxSettings settings)
        {
            _applicationKey = settings.ApplicationKey;
            _applicationSecret = settings.ApplicationSecret;
            _accessTokenPath = settings.AccessTokenPath;
            SetupApiRestClient();
            SetupContentRestClient();
        }

        private void SetupApiRestClient()
        {
            _apiRestClient = new OAuthRestClient("https://api.dropbox.com");
            _apiRestClient.ConsumerKey = _applicationKey;
            _apiRestClient.ConsumerSecret = _applicationSecret;
            _apiRestClient.Version = _version;
        }

        private void SetupContentRestClient()
        {
            _contentiRestClient = new OAuthRestClient("https://api-content.dropbox.com");
            _contentiRestClient.ConsumerKey = _applicationKey;
            _contentiRestClient.ConsumerSecret = _applicationSecret;
            _contentiRestClient.Version = _version;
        }

        public OAuthToken GetRequestToken()
        {

            return new OAuthToken(_apiRestClient.GetRequestToken("1/oauth/request_token"));

        }

        public void AuthorizeToken(OAuthToken token)
        {
            Process.Start("https://www.dropbox.com/1/oauth/authorize?oauth_token=" + token.Token);
        }

        public void SetAccesToken()
        {
            OAuthToken accesToken = GetAccesTokenFromStore();
            if (accesToken == null)
            {
                OAuthToken requestToken = GetRequestToken();
                AuthorizeToken(requestToken);
              //  accesToken = UpgradeRequsetTokenToAccesToken(requestToken);
            }

            _accessToken = accesToken;
        }

        public void UpgradeRequsetTokenToAccesToken(OAuthToken requestToken)
        {
            if (requestToken == null)
                return;

            string tokenString = _apiRestClient.GetAccesToken("1/oauth/access_token", requestToken);
            OAuthToken token = new OAuthToken(tokenString);
            StoreAccessToken(tokenString);

        }

        public void StoreAccessToken(string tokenString)
        {
            FileStream fs = File.Open(_accessTokenPath, FileMode.OpenOrCreate, FileAccess.ReadWrite);
            StreamWriter sw = new StreamWriter(fs);
            sw.WriteLine(tokenString);
            sw.Close();
            fs.Close();

        }

        private OAuthToken GetAccesTokenFromStore()
        {
            OAuthToken token = null;
            string tokenString = TokenStringFromFile();
            if (!string.IsNullOrEmpty(tokenString))
                token = new OAuthToken(tokenString);

            return token;
        }

        private string TokenStringFromFile()
        {
            FileStream fs = File.Open(_accessTokenPath, FileMode.OpenOrCreate, FileAccess.ReadWrite);
            StreamReader sw = new StreamReader(fs);

            string tokenString = sw.ReadToEnd();
            sw.Close();
            fs.Close();
            return tokenString;
        }

        public AccountInfo AccountInfo()
        {
            var response = _apiRestClient.QueryServer<AccountInfo>("1/account/info", GetAccesTokenFromStore());
            return response;
        }

        public FileEntry GetMetadata(string path)
        {
            string requestPath = "1/metadata/dropbox";
            if (!String.IsNullOrEmpty(path))
                requestPath = String.Format("{0}{1}", requestPath, path.ToLower());
            var response = _apiRestClient.QueryServer<FileEntry>(requestPath, GetAccesTokenFromStore());
            return response;
        }

        public byte[] GetFile(string path)
        {
            var response = _contentiRestClient.GetStream("1/files/" + path, GetAccesTokenFromStore());
            return response;
        }
    }

Since this i an early release I’ve build this simple .aspx page that provides the user with a link to allow acces to their dropbox and writes the accesToken to a flat file, the file can we then copy to the sitecore data folder for later use.

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
</head>
<body>
    <form id="form1" runat="server">
    <div>

    Token : <%# Token.Token %> <br />
    Token Secret  <%# Token.TokenSecret %><br />

    <a href="https://www.dropbox.com/1/oauth/authorize?oauth_token=<%# Token.Token %>" target="_blank">Autherize Dropbox</a>

    <asp:Button ID="Button2" Text="Store Token" runat="server" onclick="Button2_Click" />
    </div>
    </form>
</body>
</html>
 public partial class AutherizeDropBox : System.Web.UI.Page
    {
        private OAuthToken token;
        private DropboxContext context;
        protected void Page_Load(object sender, EventArgs e)
        {
            context = new DropboxContext(SitecoreDropboxSettingsRepository.Get());

            if (!IsPostBack)
            {

                DataBind();
            }
        }

        protected void Page_PreRender(object sender, EventArgs e)
        {

        }

        protected  OAuthToken Token
        {
            get
            {
                if (ViewState["token"] != null)
                {
                    token = new OAuthToken();
                    token.Token = ViewState["token"].ToString();
                    token.TokenSecret = ViewState["tokenSecret"].ToString();
                }
                if (token == null)
                {
                    token = context.GetRequestToken();
                    ViewState["token"] = token.Token;
                    ViewState["tokenSecret"] = token.TokenSecret;
                }
                return token;
            }
        }

        protected void Button2_Click(object sender, EventArgs e)
        {

                OAuthToken t = Token;
                context.UpgradeRequsetTokenToAccesToken(t);

        }
    }

For dropbox context to work we need a valid dropboxcontext setting datacontainer. Information for this i stored as settings in the web.config

   <setting name="ApplicationKey" value="YOURAPPLIKATIONKEY" />
   <setting name="ApplicationSecret" value="YOURAPPLIKATIONSECRET" />
   <setting name="AccessTokenPath" value="PATHTOYOUFILETHATCONTAINSACCESSTOKEN" />

For this simple version of dropbox syncing I’ve build a simple sitecore task to run a “Download all service” from dropbox. It’s start by deleting all old the previously downloaded content from dropbox and the download from all content from dropbox root ie. “dropbox/”.

public class DropboxDownloadTask
    {
        CreateMediaItemService _createMediaItemService;
        public void Execute()
        {
            _createMediaItemService = new CreateMediaItemService();
            GetRoot();
        }

        private void GetRoot()
        {
            MetatadataRepository metatadataRepository = new MetatadataRepository();
            FileEntry root = metatadataRepository.Get();
            IterateOverChildren(root);
        }

        private void  IterateOverChildren(FileEntry folderEntry)
        {

            foreach (FileEntry entry in folderEntry.Contents)
            {
                if (entry.Is_Dir)
                  IterateOverChildren(GetFileEntry(entry));
                else
                  _createMediaItemService.CreateMediaItem(entry);
            }
        }

        private FileEntry GetFileEntry(FileEntry entry)
        {
            MetatadataRepository metatadataRepository = new MetatadataRepository();
            return metatadataRepository.Get(entry);
        }
    }

The task uses some file- and metadata-repositories that communicate with dropboxcontext and a simple settings repository.

 public static class SitecoreDropboxSettingsRepository
    {
        public static DropBoxSettings Get()
        {
            DropBoxSettings settings = new DropBoxSettings();
            settings.ApplicationKey = Settings.GetSetting("ApplicationKey");
            settings.ApplicationSecret = Settings.GetSetting("ApplicationSecret");
            string path = Settings.GetSetting("AccessTokenPath");
            settings.AccessTokenPath = HttpContext.Current.Server.MapPath(path);
            return settings;
        }

    }
public class MetatadataRepository
    {
        private DropboxContext _context;
        public MetatadataRepository()
        {

            _context = new DropboxContext(SitecoreDropboxSettingsRepository.Get());
        }

        public FileEntry Get()
        {
            return _context.GetMetadata(String.Empty);
        }

        public FileEntry Get(FileEntry entry)
        {
          return _context.GetMetadata(entry.Path);
        }
    }
 public class FileDataRepository
    {
        private  DropboxContext _context;
        public FileDataRepository()
        {

            _context = new DropboxContext(SitecoreDropboxSettingsRepository.Get());
        }

        public  byte[] Get(FileEntry entry)
        {
          return _context.GetFile(entry.Root+entry.Path);
        }
    }

Finally the task have a simple service that is responsible for adding a media stream to the sitecore media library.

 public class CreateMediaItemService
    {

        private MediaCreator _creator;
        private MediaCreatorOptions _mediaOptions;

        public void CreateMediaItem(FileEntry folderName)
        {
                 using (new SecurityDisabler())
                          AddStreamToMediaLibrary(folderName);

        }

        private void AddStreamToMediaLibrary(FileEntry folderName)
        {
             if(folderName.Parent == "dropbox")
                 SetMediaOptions(folderName.Parent, folderName.Name);
            else
                SetMediaOptions(String.Format("dropbox/{0}",folderName.Parent), folderName.Name);
            _creator = new MediaCreator();

            FileDataRepository fileDataRepository = new FileDataRepository();
            byte[] bytes = fileDataRepository.Get(folderName);

            MemoryStream theMemStream = new MemoryStream();

            theMemStream.Write(bytes, 0, bytes.Length);
            try
            {

                    _creator.CreateFromStream(theMemStream, folderName.Name, _mediaOptions);
            }
            catch (Exception e)
            {
                throw new Exception(folderName.Name, e);
            }
        }

        private void SetMediaOptions(string sitecorePath, string itemName)
        {
            _mediaOptions = new MediaCreatorOptions();
            _mediaOptions.FileBased = false;
            _mediaOptions.IncludeExtensionInItemName = false;
            _mediaOptions.KeepExisting = false;
            _mediaOptions.Versioned = false;
            _mediaOptions.Destination = String.Format("/sitecore/media library/{0}/{1}", sitecorePath, ItemUtil.ProposeValidItemName(itemName));
            _mediaOptions.Database = Database.GetDatabase("master");

        }

    }

Offcourse there are room for improvement and the code could use some cleaning up to is more “Clean Code” Uncle Bob.  You can download the source code for this project at Pentia. I’m more then interrested in hearing what features should be on the todo-list so let me know.

Categories: .Net, C#, Sitecore 6 Tags: , ,
  1. No comments yet.
  1. No trackbacks yet.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: