Monday, March 16, 2009 - Posts

Monday, March 16, 2009
via @fractalnavel: in the last twenty-four hours:
  • Mon Mar 16 18:16:59 +0000 2009: if i added up all the "10 tips to ..." type things that i've run into, how many would that be ?
  • Mon Mar 16 22:49:18 +0000 2009: done, done, done - for now: http://tinyurl.com/crwtv7
  • Mon Mar 16 22:55:39 +0000 2009: pizza is as pizza does: http://larosas.com - saving housebound geeks from starvation, since (whenever they went online)
  • Mon Mar 16 23:28:00 +0000 2009: @klaatu but then we'd have the meta top n meta top n list... ad nauseum. that would be either very hard or very easy to come up with
  • Mon Mar 16 23:29:05 +0000 2009: @craigg thhppptttt!! :-p
  • Mon Mar 16 23:31:44 +0000 2009: @craigg75 the raspberry was meant for you - sorry, @craigg
(pulled direct from twitter via custom cs job)
Posted by fractalnavel at 11:30 PM | with no comments
a better way to daily post twitter to community server: just do a console app, use the metablog api, and task scheduler

scratch that last cvrap, replace the GetAndPostJob class with the following, making the whole thing a console app to run from the task scheduler:

    class CMain
    {
        [STAThread]
        static void Main(string[] args)
        {
            //do work
            XmlDocument xmldocSettings = new XmlDocument();
            xmldocSettings.Load( args[0]);
            GetAndPost gap = new GetAndPost(xmldocSettings.DocumentElement);
            if ( gap.Get() ) {
                gap.Transform();
                gap.Post();
            } else if ( xmldocSettings.Attributes["bPostNone"].Value == "true" ) {
                gap.Post( "nothin'" );
            }
        }
    }

    [XmlRpcUrl("http://blogs.no-ip.org/fractalnavel/metablog.ashx")] 
    public interface IMetaWebLogNewPost
    {
        [XmlRpcMethod("metaWeblog.newPost")]
        string newPost(
            string blogid,
            string username,
            string password,
            MetaWeblog.Post post,
            bool publish);
    }

and replace the last couple of lines in the Post method:

    
            IMetaWebLogNewPost mwlProxy = XmlRpcProxyGen.Create<IMetaWebLogNewPost>();
            string ret = mwlProxy.newPost( blogid, userid, pwd, p, bPublish);

there's really no good way to get an "at" functionality from cs tasks (unless there's something undocumented; can't tell from the obfuscated code).  i mean shoot, i was going to end up recreating the whole scheduler business, may as well just use the thing.

duh.

yeah, all the rest of the stuff needs cleaning, of course, but this will at least do what i want, when i want.

oh yeah - the argument to the app is the name of a file that contains the task node that used to be in communityserver.config, minus the community server specific stuff.  i suppose i could use an actual config file; this was a straight forward adaptation of the previous approach.

whatever.  just getting things done.  i'm not in a very ocd mood.  that's what happens with (b) fueled code, instead of (c).

Posted by fractalnavel at 6:23 PM | 1 comment(s)
Filed under: , ,
a first shot at a community server task/job to auto-aggregate & -post my daily twitter timeline.

been playing with auto-capturing daily twittering & posting here.  not that i use twitter much; pehaps this auto-posting lack is why.  at first i tried  loudtwitter, but community server doesn't have a way of accepting what it provides out of the box - email (needs cs enterprise license), atom, xmlrpc (what api?).  so i had it email to tumblr, and then mirrored the feed from there (needs cs pro license).  you may have seen the recent example of that.  either i did something grossly wrong somewhere, or either loudtwitter or tumblr is eating the markup.  and the post naming would cause problems with my current url rewriting scheme - i just noticed that.  huh - no wonder it didn't post last night.

none of this was very acceptable (or even workable).  i suppose i could have figured out what xmlrpc was being sent from loudtwitter and then used that (a more portable solution - still wopuld have the bad post naming).  funny that there's nothing about anyone doing this anyplace that i can see.  just me, i guess. and no, still no a.p.p. in cs2008.5sp1 (i upgraded last week).

apparently, i chose the "roll your own" route (see below), but it's not finished.  well, it works, but i need to tweak scheduling and formatting, and generalizing the configuration would be nice, as would fixing the credential security issue.  but hey, this is just for me.  all that detail stuff is a lot of work.

not a sterling example of code or design, but, well, any landing you can walk away from ...

  • fractalnavel.CS.Components.GetAndPostJob
    /*
    get xml, transform to post, post to blog.
    
    ***twitter specific at the moment.***
    
    config is as follows for now, until controlpanel stuff is done:
        hrefget - get: string (must return results as xml; basically assuming a rest interface)
        useridGet, pwdget - get: authentication = userid, password (yeah, not very secure, need to do something different)
        hrefXsl - transform reference (url; this xslt is applied to the "get" xml, and will result in the post body)
        idBlog - post: destination blog
        useridBlog, pwdBlog - post: authentication (userid, password) (again, security issue)
        titleBlog - post title (appended with date)
        hours - how far back to look
        bPostNone - post when nothing was retrieved ?
    
    also, should log processing status to events...
    */
    
    using System;
    using System.IO;
    using System.Net;
    using System.Text;
    using System.Xml;
    using System.Xml.Xsl;
    
    using CommunityServer.Blogs.Components;
    
    using Telligent.Tasks;
    
    
    namespace fractalnavel.CS.Components
    {
    
        // the job
        public class GetAndPostJob : ITask
        {
    
            public GetAndPostJob()
            {
            }
    
            public void Execute(XmlNode node)
            {
                //do work
                GetAndPost gap = new GetAndPost(node);
                if ( gap.Get() ) {
                    gap.Transform();
                    gap.Post();
                } else if ( node.Attributes["bPostNone"].Value == "true" ) {
                    gap.Post( "nothin'" );
                }
            }
        }
    
        // the work
        public class GetAndPost
        {
            private XmlNode _nodSettings;
            private string _strPostBody;
            private XmlDocument _xmldocAll = new XmlDocument();
            
            public GetAndPost( XmlNode node )
            {
                _nodSettings = node;
            }
            
            public bool Get() 
            {
                string href = _nodSettings.Attributes["hrefGet"].Value;
                int intHours = Int32.Parse(_nodSettings.Attributes["hours"].Value);
                // Tue%2C+27+Mar+2007+22%3A55%3A48+GMT
                href += "?since=" + ((DateTime.Now).AddHours(-intHours)).ToString("r");
                string userid = _nodSettings.Attributes["useridGet"].Value;
                string pwd = _nodSettings.Attributes["pwdGet"].Value;
                _strPostBody = GetTextFromHref( href, userid, pwd );
                _xmldocAll.LoadXml( _strPostBody );
                return (_xmldocAll.SelectNodes("//status")).Count > 0;
            }
            
            public void Transform()
            {
                string href = _nodSettings.Attributes["hrefXsl"].Value;
                XslTransform xsl = new XslTransform();
                xsl.Load( href, new XmlUrlResolver() );
                StringBuilder sbResult = new StringBuilder();
                StringWriter swResult = new StringWriter( sbResult );
                xsl.Transform( _xmldocAll, null, swResult, null );
                _strPostBody = sbResult.ToString();
            }
            
            public void Post()
            {
                Post( _strPostBody );
            }
            
            public void Post( string strPostBody )
            {
                string blogid = _nodSettings.Attributes["idBlog"].Value;
                string userid = _nodSettings.Attributes["useridBlog"].Value;
                string pwd = _nodSettings.Attributes["pwdBlog"].Value;
                string title = _nodSettings.Attributes["titleBlog"].Value;
                bool bPublish = true;
                DateTime dtNow = DateTime.Now;
                MetaWeblog.Post p = new MetaWeblog.Post();
                p.title = title + " " + (dtNow).ToString("yyyy.MM.dd");
                p.dateCreated = dtNow;
                p.description = strPostBody;
                IMetaWeblog metablog = new MetaWeblog();
                metablog.newPost(blogid, userid, pwd, p, bPublish);
            }
    
            private string GetTextFromHref(string url, string user, string password)
            {
                HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(url);
                request.Credentials = new NetworkCredential(user, password);
                WebResponse response = request.GetResponse();
                StreamReader reader = new StreamReader(response.GetResponseStream());
                string responseString = reader.ReadToEnd();
                reader.Close();
                return responseString;
            }
        }
    
    }
  • excerpt from communityserver.config
    ...
    <!-- 2009.03.15, css: added for daily twitter summary post; daily update relies on daily app pool cycling !! -->
    <Thread minutes="1320">
        <task 
            name = "fnGetAndPostJob" 
            type = "fractalnavel.CS.Components.GetAndPostJob, fractalnavel.CS" 
            enabled = "true" 
            enableShutDown = "false" 
            hrefGet="http://twitter.com/statuses/user_timeline.xml" 
            useridGet="***" 
            pwdGet="***" 
            hrefXsl="http://blogs.no-ip.org/GetAndPost.xsl" 
            idBlog="fractalnavel" 
            useridBlog="***" 
            pwdBlog="***" 
            titleBlog="a day in a life" 
            hours="24" 
            bPostNone="false" 
            />
    </Thread>
    ...
  • GetAndPost.xsl
    <?xml version="1.0" ?>
    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" >
        
    <xsl:output method='html' 
                omit-xml-declaration="yes"
                version="1.0"
                encoding="UTF-8"
                indent="yes"
                cdata-section-elements=""
                /> 
        
        <xsl:template match="/statuses">
    
            <div class="divLTAll">
    
                <div class="divLTHead">
                    via <a href="http://www.twitter.com/fractalnavel" target="_blank" 
                    title="twitter!">@fractalnavel</a>: in the last twenty-four hours:
                </div>
            
                <div class="divLTBody">
                    <ul>
                        <xsl:apply-templates select="status" >
                            <xsl:sort select="position()" order="descending" data-type="number"/>
                        </xsl:apply-templates>
                    </ul>
                </div>
    
                <div class="divLTFoot">
                    (pulled direct from twitter via custom cs job)
                </div>
                
            </div>
    
        </xsl:template>
    
        <xsl:template match="status">
            <li><xsl:value-of select="created_at" />: <xsl:value-of select="text" /></li>
        </xsl:template>
    
    </xsl:stylesheet>

so the intent should be clear anyway. 

there were a lot of links that assisted in one way or another, but the power went phlooey this morning for no apparent reason (interestingly, my modem/router was presciently bombing just minutes before that), so that combined with my laziness means you won't see them here.  mostly just stuff on generic community server task creation, and the twitter api.

other twitter related stuff to-do:

  • do an updated CSModule for updating twitter when a post is created.  there is an old one out there.  somewhere.  but my data stream is heading the other direction.
  • do a sidebar widget with ajaxy & configurable timeline display.  have it update & scroll, that sort of thing.  eh, for the addicts out there, sure, but for me ?  nahhh...

i did finally do something twitter-ish on the xo: installed TTYtter.  too bad there's not a sugar-ized gui client.  and it seems any other linux friendly gui twitter clients will bloat too much once all the supporting stuff gets put in place.  best to do that on an xo running linux on a stick.  seriously, what's the issue with expanding the storage there ?  for just a few bucks more, could increase it by an order of magnitude.  but it's easy being an armchair couch quarterback.

Posted by fractalnavel at 1:50 PM | 1 comment(s)
Filed under: , , ,