Dustin Gibson

Favors App (Java, Python, SQL)


Favors is a service classifieds mobile app based on user’s location. Users can register or login for the service and post or respond to service classifieds. Users can also approve or disapprove applicants as well as send instant messages.

Code samples are posted at the bottom of this page

Git Link
Latest Android APK (not signed) June 8th, 2016
Client: Java
Server: Python (Django Framework and Twisted), SQL (postgreSQL), Linux


In Progress:
  • Edit Favor
  • Feeds
  • Search Favor
  • View Profile
  • Search Profile


Server My server hosted using Linux (Ubuntu 12.04). The webserver I used is NGINX with Gunicorn. The backend is built using Django. The messaging uses Python’s Twisted library for sending and receiving TCP packets. Data is stored using the PostgreSQL database.

Data Model (click to enlarge)

Code Details
  • Object Oriented – My design philosophy for this particular application is to take advantage of design patterns and build code based on re-usability and easy modification. Through out the code base you’ll see numerous design patters such as Singleton, Adapter, Factory, and Facade.
  • ORM - Django takes advantage of ORM technique to perform queries, insertions, and updates. Each table represents a column and each column represents a variable or an instance of an object.
  • Async - The application is designed to handle multiple tasks at once. Android provides a very nice thread-safe async package. For an example: the application is able to update a listview while checking for any incoming messages without running into concurrency issues.
  • Fragments and Activities - The application have two activities: home and user activity. The home activity is bound to the menu object and everywhere else uses the user activity. Inside each activity are fragments. The home activity, for an example, have nearby favors and asssigned favors fragment. Each fragment and activity represents a single class.
  • Messaging - Due to the demanding nature of instant messaging, the app uses TCP as opposed to HTTP to send and receive instant messages. Having a delay in response or racking up a sizable amount of limited mobile data is unacceptable for a mobile application. The amount of overhead for a HTTP message is large compared to a TCP packet. Sending and receiving messages from a TCP packet is considerably less expensive.


Challenges and Lessons Learned

  • Since I lack any formal information systems formal training, putting together the server was incredibly difficult.
  • Resigning the code to go from using a HTTP based messaging model to a TCP based messaging model.
  • Understanding the lifecycle of fragment and activities as well as how events work in Android.
  • I professionally use Oracle SQL and used MySQL at school. PostgreSQL had a lot of noticeable differences.
  • Mobile UI design was a lot more complicated than I thought. I had to constantly redesign the UI to make the application more user friendly.
Code Samples:

Get Favors List (Python)

			
				

def get_favors_list(request):
	json_message = []
	if request.method == 'GET':
		if request.user.is_authenticated():
			try:
				location_zip = request.COOKIES.get('zip')
				session = Session.objects.get(session_key=request.session.session_key)
				user_id = session.get_decoded().get('_auth_user_id')
				existing_user = User.objects.get(pk=user_id)
				existing_profile = models.UserProfile.objects.filter(ldap_user=existing_user)[0]
				nearby_locations = models.LocationDistance.objects.filter(from_location_fk_id=location_zip).order_by('distance')
				onlocation_favors = models.Favor.objects.filter(location_fk_id=location_zip).exclude(creator_fk=existing_profile)
				for nearby_location in nearby_locations:
					try:
						current_city = models.PresetLocation.objects.filter(presetlocation_id=nearby_location.to_location_fk_id)[0]
						current_favors = models.Favor.objects.filter(location_fk_id=nearby_location.to_location_fk).exclude(creator_fk=existing_profile)
						for current_favor in current_favors:
							thumb_images = models.FavorImage.objects.filter(favor_fk=current_favor)
							current_candidate = models.Candidate.objects.filter(favor_fk=current_favor,candidate_fk=existing_profile)
							if thumb_images.exists():
								thumb_image = thumb_images[0]
							else:
								thumb_image = None
							favors_dump = {}
							favors_dump['favorid'] = str(current_favor.favor_id)
							favors_dump['title'] = current_favor.title
							favors_dump['zip'] = str(current_favor.location_fk_id)
							favors_dump['city'] = current_city.city
							favors_dump['state'] = current_city.state
							favors_dump['distance'] = str(nearby_location.distance)
							if current_candidate.exists():
								favors_dump['status'] = current_candidate[0].status
							else:
								favors_dump['status'] = 'None'
							if thumb_image == None:
								favors_dump['thumb'] = 'None'
							else:
								favors_dump['thumb'] = thumb_image.image_path
							favors_dump['date'] = current_favor.date_created.strftime('%B %d, %Y %I:%M %p')
							favors_dump['deadline'] = current_favor.deadline.strftime('%m/%d/%Y %I:%M %p')
							json_message.append(favors_dump)
					except:
						print "ERROR WITH FAVOR LIST"
						traceback.print_exc()
						return HttpResponse("Issue retrieving data")
				current_city = models.PresetLocation.objects.filter(presetlocation_id=location_zip)[0]
				for onlocation_favor in onlocation_favors:
					thumb_images = models.FavorImage.objects.filter(favor_fk=onlocation_favor)
					current_candidate = models.Candidate.objects.filter(favor_fk=onlocation_favor,candidate_fk=existing_profile)
					if thumb_images.exists():
						thumb_image = thumb_images[0]
					else:
						thumb_image = None
					favors_dump = {}
					favors_dump['favorid'] = str(onlocation_favor.favor_id)
					favors_dump['title'] = onlocation_favor.title
					favors_dump['zip'] = str(onlocation_favor.location_fk_id)
					favors_dump['city'] = current_city.city
					favors_dump['state'] = current_city.state
					favors_dump['distance'] = '0'
					if thumb_image == None:
						favors_dump['thumb'] = 'None'
					else:
						favors_dump['thumb'] = thumb_image.image_path
					if current_candidate.exists():
						favors_dump['status'] = current_candidate[0].status
					else:
						favors_dump['status'] = 'None'
					favors_dump['date'] = onlocation_favor.date_created.strftime('%B %d, %Y %I:%M %p')
					favors_dump['deadline'] = onlocation_favor.deadline.strftime('%m/%d/%Y %I:%M %p')
					json_message.append(favors_dump)
				return HttpResponse(json.dumps(json_message))
			except:
				traceback.print_exc()
				return HttpResponse("Issue getting location")
		else:
			return HttpResponse("User not logged in")
	else:
		return HttpResponse("Wrong method")