Back Story
So after having our baby early, I wanted a convenient way to share pictures and updates to the family and I thought what better way than Twitter. So we set our baby up with a Twitter account and set it to protected. I found the best way to post pictures is through TwitPic, but found that when people post comments through TwitPic, the links show up on their Twitter page. Obviously this defeats the point of making her account protected since the main thing we wanted to protect was the pictures. We also know that it is extremely difficult to protect pictures on the Web, but we like to make it somewhat difficult for weirdos.
My solution to the problem is to write a small app so I can post a pic and a status from my iPhone and have it somewhat secure. I'm going to use Twitterizer as my C# Twitter framework, SQL 2008, and ASP.NET MVC. The flow will go like this...
if not authenticated to Twitter
authenticate
if a follower of the baby
show pic and allow comments
(comments will post to the viewer's Twitter like this: "@baby STP:1234 comment here")
Notice there is not a link to the picture, but still a reference so the baby knows which pic they're talking about
else
deny access to pic
As of right now, I have two services, ITwitterService & IUploadService, which look like this:
public interface ITwitterService
{
void Update(string status);
bool IsAuthenticated { get; }
}
public interface IUploadServiceHere's my implementation:
{
void Upload(HttpRequestBase request);
}
public class TwitterService : ITwitterService
{
private readonly Twitter _twitter;public class UploadService : IUploadService
private readonly string _username;
private readonly string _password;
public TwitterService(string username, string password) : this(username, password, null) {}
public TwitterService(string username, string password, string source)
{
_username = username;
_password = password;
if (string.IsNullOrEmpty(source))
_twitter = new Twitter(_username, _password);
else
_twitter = new Twitter(_username, _password, source);
}
public void Update(string status)
{
if (!string.IsNullOrEmpty(status))
_twitter.Status.Update(status);
}
public bool IsAllowed(string username)
{
var paras = new TwitterParameters();
paras.Add(TwitterParameterNames.ScreenName, username);
return _twitter.User.Followers(paras).Count > 0;
}
public bool IsAuthenticated
{
get { return Twitter.VerifyCredentials(_username, _password); }
}
}
{
public void Upload(HttpRequestBase request)
{
foreach (string file in request.Files)I ended up creating a helper service that takes the Twitter & Upload interfaces to do the upload and post at once…pretty simple.
{
var hpf = request.Files[file];
if (hpf.ContentLength == 0)
continue;
var savedFileName = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, Path.GetFileName(hpf.FileName));
hpf.SaveAs(savedFileName);
}
}
}
public class STPService
{
private readonly ITwitterService _twitterservice;Here are my integration tests:
private readonly IUploadService _uploadservice;
public STPService(ITwitterService twitterService, IUploadService uploadService)
{
_twitterservice = twitterService;
_uploadservice = uploadService;
}
public void UploadAndPost(HttpRequestBase request, string status)
{
_uploadservice.Upload(request);
_twitterservice.Update(status);
}
}
[TestFixture]
public classTwitterTests
{
[Test]
public voidIsAuthenticated_user_is_authenticated_returns_false()
{
var twit = newTwitterService("baby", "badpassword");
Assert.IsFalse(twit.IsAuthenticated);
}
[Test]
public voidIsAuthenticated_user_is_authenticated_returns_true()
{
var twit = newTwitterService("baby", "password");
Assert.IsTrue(twit.IsAuthenticated);
}
[Test]
public voidIsAllowed_user_is_not_allowed_returns_false()
{
var twit = newTwitterService("baby", password");
Assert.IsFalse(twit.IsAllowed("test"));
}
[Test]
public voidIsAllowed_user_is_allowed_returns_true()
{
var twit = newTwitterService("baby", "password");
Assert.IsTrue(twit.IsAllowed("derans"));
}
}
I started with the default ASP.NET MVC stuff and just started modifying it. I added a method to the HomeController like this:
[AcceptVerbs(HttpVerbs.Post)]
publicActionResult Index(stringstatus)
{
var stpService = DI.CreateSTPService();
stpService.UploadAndPost(Request, status);
ViewData["UploadMessage"] = "Posted.";
returnView();
}
<%using(Html.BeginForm("Index", "Home", FormMethod.Post, new { enctype = "multipart/form-data" }))I added a couple HTML Helper Extension methods in a helper file.
{ %>
<p><%=Html.Label("file", "Picture to Upload:") %><br />
<%=Html.File("file") %></p>
<p><%=Html.Label("status", "Status:") %><br />
<%=Html.TextArea("status", "", 5, 30, null) %></p>
<input type="submit" name="submit" value="Send" />
<%=Html.Encode(ViewData["UploadMessage"])%>
<% } %>
public static classHtmlExtensions
{
public static stringLabel(thisHtmlHelper html, stringtarget, stringtext)
{
returnString.Format("<label for=\"{0}\">{1}</label>", target, text);
}
public static stringFile(thisHtmlHelper html, stringname)
{
returnString.Format("<input type=\"file\" name=\"{0}\" id=\"{0}\" />", name);
}
}