예제 #1
0
def verifyUser():
	"""
	REDUNDANT
	Verifying the user from the confirmation mail sent using POST method

	"""
	response = {}
	data = {}
	userObj = Collection()
	clientObj = Collection()
	tokenObj = Collection()

	obj = request.json
	try:
		userObj.email = obj["email"]
		userObj.key = obj["key"]
		flag = bll.verifyUser(userObj)
		if flag:
			response["status"] = RESPONSE_SUCCESS
			response["message"] = "Verification Sucessful"
		else:
			response["status"] = RESPONSE_FAILED
			response["message"] = "Verification Unsucessful"
	except Exception as e:
		response['status'] = RESPONSE_FAILED
		response['message'] = str(e)
		if hasattr(e, "code"):
			response["code"] = e.code
	return response
예제 #2
0
def syncUserInfo():
	"""
	Suny the basic information of the user like:
	id, name, email and addProfilePic
	"""
	userObj = Collection()
	clientObj = Collection()
	tokenObj = Collection()
	jsonResponse = {}
	
	try:
		jsonObj = request.json
		jsonResponse["status"] = RESPONSE_SUCCESS
	except Exception as e:
		jsonResponse["status"] = RESPONSE_FAILED
	jsonResponse["data"] = []
	userObj.access_token = jsonObj["access_token"]
	for obj in jsonObj["data"]:
		response = {}
		data = {}
		try:
			userObj.email = obj["email"]
			if bll.checkAccessTokenValid(userObj):
				user = bll.syncUserInfo(userObj)
			response["data"] = bll.convertUserToDict(user)
			response["status"] = RESPONSE_SUCCESS
		except Exception as e:
			response['status'] = RESPONSE_FAILED
			response['message'] = str(e)
			if hasattr(e, "code"):
				response["code"] = e.code
		jsonResponse["data"].append(response)
	return jsonResponse
예제 #3
0
def refreshTokens():
	"""
	Using the refresh_token to generate new acceess_token

	route(/user/refreshTokens)

	"""
	response = {}
	data = {}
	userObj = Collection()
	clientObj = Collection()
	tokenObj = Collection()

	obj = request.json
	try:
		tokenObj.refresh_token = obj["refresh_token"]
		new_token = bll.refreshTokens(tokenObj)
		token = bll.updatetoken(new_token)
		data["refresh_token"] = token.refresh_token
		data["access_token"] = token.access_token
		data["expiresAt"] = token.expiresAt
		response["data"] = data
		response["message"] = RESPONSE_SUCCESS
	except Exception as e:
		response['status'] = RESPONSE_FAILED
		response['message'] = str(e)
		if hasattr(e, "code"):
			response["code"] = e.code
	return response
예제 #4
0
def modifyProfilePic():
	"""
	Add a profile pic to the user account
	"""
	response = {}
	data = {}
	userObj = Collection()
	clientObj = Collection()
	tokenObj = Collection()

	photoObj = Collection()
	img = request.files.get('image')
	print img
	try:
		photoObj.filename, photoObj.extension = os.path.splitext(img.filename)
		photoObj.image = img
		photoObj.contentType = request.forms.get('contentType')
		photoObj.acceess_token = requests.headers.get('Authorization')
		photoObj.id = requests.headers.get('User-ID')
		bll.addProfilePic(photoObj)
		response["status"] = RESPONSE_SUCCESS
	except Exception as e:
		response['status'] = RESPONSE_FAILED
		response['message'] = str(e)
		if hasattr(e, "code"):
			response["code"] = e.code
	return response
예제 #5
0
def register():
	"""
	View for user registration

	route(/user/register)

	"""
	response = {}
	data = {}
	userObj = Collection()
	clientObj = Collection()
	tokenObj = Collection()

	obj = request.json
	try:
		userObj.email = obj["email"]
		userObj.name = obj["name"]
		userObj.password = obj["password"]
		try:
			userObj.authMethod = obj["authMethod"]
		except KeyError as e:
			userObj.authMethod = "taskieAuth"
		try:
			userObj.serverPushId = obj["serverPushId"]
		except KeyError as e:
			userObj.serverPushId = ''
		user = bll.createUser(userObj)
		response['status'] = RESPONSE_SUCCESS
		response['data']  = bll.convertUserToDict(user)
	except Exception as e:
		response['status'] = RESPONSE_FAILED
		response['message'] = str(e)
		if hasattr(e, "code"):
			response["code"] = e.code
	return response
예제 #6
0
def addCollaborators(taskObj):
    """
	Add collaborators to an existing task

	:type taskObj: object
	:param An instance with the following attributes
			collaborators
	:return An instance of the Task class

	"""
    my_objects = []
    userObj = Collection()
    groupObj = Collection()

    #Obtain the group using id
    groupObj.id = taskObj.group_id
    taskgroup = getGroupById(groupObj)

    #Obtain the task using task is
    task = getTaskById(taskObj)

    #Create a Status object to assign to each collaborator
    taskObj.status = Status(status=0, dateTime=time.time())

    #Checking existence of collaborators
    for userObj.email in taskObj.collaborators:
        user = userbll.getUserByEmail(userObj)
        if not [x for x in taskgroup.members if x.id == user.id]:
            raise UserNotMember
        my_objects.append(Collaborator(user=user, status=taskObj.status))

    GroupTask.objects(id=task.id).update(push_all__collaborators=my_objects)
    task.save()
    task.reload()
    return task
예제 #7
0
def updateUser():
	"""
	Updating user information

	route(/user/updateUser)
	"""
	response = {}
	data = {}
	userObj = Collection()
	clientObj = Collection()
	tokenObj = Collection()
	obj = request.json
	try:
		userObj.email = obj["email"]
		userObj.name = obj["name"]
		userObj.key = obj["key"]
		try:
			userObj.serverPushId = obj["serverPushId"]
		except KeyError as e:
			userObj.serverPushId = ''
		user = bll.updateUser(userObj)
		data["user"] = bll.convertUserToDict(user)
		response["status"] = RESPONSE_SUCCESS
		response["data"] = data
	except Exception as e:
		response['status'] = RESPONSE_FAILED
		response['message'] = str(e)
		if hasattr(e, "code"):
			response["code"] = e.code
	return response
예제 #8
0
def checkAccessToken(tokenObj):
	"""
	Checking whether the given access_token is valid or not

	"""
	response = {}
	data = {}
	userObj = Collection()
	clientObj = Collection()
	tokenObj = Collection()

	try:
		token = bll.checkAccessTokenValid(tokenObj)
		if token.flag:
			response["status"] = RESPONSE_SUCCESS
			response["message"] = "TOKEN_VALID"
		else:
			response["status"] = RESPONSE_FAILED
			response["message"] = "TOKEN_INVALID"
	except Exception as e:
		response['status'] = RESPONSE_FAILED
		response['message'] = str(e)
		if hasattr(e, "code"):
			response["code"] = e.code
	return response
예제 #9
0
def addCollaborators(taskObj):
    """
	Add collaborators to an existing task

	:type taskObj: object
	:param taskObj: An instance with the following attributes
					collaborators
	:return An instance of the Task class

	"""

    my_objects = []
    userObj = Collection()

    #Assigning initial status to each collaborator
    taskObj.status = Status(status=0, dateTime=time.time())

    task = getTaskById(taskObj)
    userObj.owner = task.owner
    #Check if new collaborators exist
    for userObj.email in taskObj.collaborators:
        try:
            #try to find the user by email from the databsae
            person = User.objects.get(email=userObj.email)
        except Exception as e:
            #If user is not found, create a new minimal users and send an invite
            person = userbll.createAndInvite(userObj)
        #Get the returned user from both cases and add create collaborators from them
        my_objects.append(Collaborator(user=person, status=taskObj.status))

    #Update the task with the new collaborator
    Task.objects(id=task.id).update(push_all__collaborators=my_objects)
    task.save()
    task.reload()
    return task
예제 #10
0
def addNewTask(taskObj):
    """
	Adds a new task to the task list

	:type taskObj : object
	:para. taskObj : An object with the following attributes
			owner,
			collaborators,
			priority,
			name,
			description,
			dueDateTime,
			status

	:return an object of the task class.

	"""

    #Assigning initial status to each task
    taskObj.task_status = Status(status=1, dateTime=time.time())
    taskObj.coll_status = Status(status=0, dateTime=time.time())

    #Define an emptly list to include all the user objects
    my_objects = []
    userObj = Collection()

    #for finding the user id of the owner
    userObj.id = taskObj.owner
    userObj.owner = userbll.getUserById(userObj)

    #Checking whether the collaborators is a user of the app
    #If not - Create a new account for the user
    for userObj.email in taskObj.collaborators:
        try:
            User.objects.get(email=userObj.email)
        except Exception:
            userbll.createAndInvite(
                userObj
            )  #contains _id = senders id and email = recievers email

    #Creating the list of collaborators
    for val in taskObj.collaborators:
        userObj.email = val
        my_objects.append(
            Collaborator(user=userbll.getUserByEmail(userObj),
                         status=taskObj.coll_status))

    #Create a task with the necessary data.
    task = Task(owner=userObj.owner,
                collaborators=my_objects,
                priority=taskObj.priority,
                name=taskObj.name,
                description=taskObj.description,
                dueDateTime=taskObj.dueDateTime,
                status=taskObj.task_status)
    task.save()
    return task
예제 #11
0
def deleteTask(taskObj):
    """Delete a task and update all collaborators about the status"""
    tempObj = Collection()
    task = dal.getTaskById(taskObj)
    tempObj.collaborators = task.collaborators
    flag = dal.deleteTask(taskObj)
    if flag is True:
        syncObj = SyncClass("Deleted", str(taskObj.id))
        pushSyncNotification(syncObj, tempObj)
    return flag
예제 #12
0
def authorize_user():
	"""
	User Login using username and password is verified

	route(/user/authorize)

	"""
	response = {}
	data = {}
	userObj = Collection()
	clientObj = Collection()
	tokenObj = Collection()

	obj = request.json
	try:
		userObj.email = obj["email"]
		try:
			userObj.authMethod = obj["authMethod"]
		except Exception, e:
			userObj.authMethod = "taskieAuth"
		try:
			userObj.password = obj["password"]
		except KeyError as e:
			userObj.password = ''
		try:
			userObj.name = obj["name"]
		except KeyError as e:
			userObj.name = ''
		cred_valid_flag = bll.authorize_user(userObj)
		if cred_valid_flag:
			userObj.user = bll.getUserByEmail(userObj)
			token = bll.getTokenByUser(userObj)
			data["id"] = str(token.user.id)
			data["name"] = userObj.user.name
			data["email"] = userObj.user.email
			data["key"] = token.key
			data["access_token"] = token.access_token
			data["refresh_token"] = token.refresh_token
			response["status"] = RESPONSE_SUCCESS
			response["data"] = data
		else:
			response["message"] = "Authorization Failed"
			response["status"] = RESPONSE_FAILED
예제 #13
0
def updatePassword(email, key):
	"""Request the password update page"""
	userObj = Collection()

	userObj.email = email;
	userObj.key = key;
	userObj.user = bll.getUserByEmail(userObj)
	token = bll.getTokenByUser(userObj)
	if token.key == userObj.key:
		return template("password_reset", flag = True, email = userObj.email, key = token.key)
	else:
		return template("password_reset", flag = False, message = "Email and Key does not match or the key has expired. Please try again")
예제 #14
0
def passwordReset():
	"""Request to reset password made by the user"""
	response = {}
	data = {}
	userObj = Collection()

	obj = request.json
	try:
		userObj.email = obj["email"]
		bll.passwordReset(userObj)
		response["status"] = RESPONSE_SUCCESS
	except Exception as e:
		response["status"] = RESPONSE_FAILED
		response["message"] = str(e)
		if hasattr(e, "code"):
			response["code"] = e.code
	return response
예제 #15
0
def taskToDictConverter(task):
    """
	Convert the incoming Task object into JSON Serializable dict format
	only including the essential details

	::type task : instance of Task class
	::param task : attributes of Task, Collaborator, Status and User Classes
	::return taskie : dictionary
	"""
    taskie = {}
    coll = {}
    status = {}
    owner = {}
    userObj = Collection()

    ## Modify task to include only all essential details
    taskie["id"] = str(task.id)
    taskie["name"] = task.name
    taskie["description"] = task.description
    taskie["dueDateTime"] = task.dueDateTime
    taskie["priority"] = task.priority
    #Setting the status
    status["status"] = task.status.status
    status["dateTime"] = task.status.dateTime
    taskie["status"] = status.copy()

    #Retrieve owner information
    owner["id"] = str(task.owner.id)
    owner["name"] = task.owner.name
    owner["email"] = task.owner.email
    taskie["owner"] = owner

    #Collaborator informaiton
    taskie["collaborators"] = []
    for each_user in task.collaborators:
        status["status"] = each_user.status.status
        status["dateTime"] = each_user.status.dateTime
        coll["id"] = str(each_user.user.id)
        coll["name"] = str(each_user.user.name)
        coll["email"] = str(each_user.user.email)
        coll["status"] = status.copy()
        coll["startTime"] = each_user.startTime
        coll["endTime"] = each_user.endTime
        taskie["collaborators"].append(coll.copy())
    return taskie
예제 #16
0
    def collDeletion(self, taskObj, task):
        message = {}
        userObj = Collection()
        message["type"] = self.NOTIFICATION_TYPE["Collaborator_Deleted"]
        message["ownerName"] = str(task.owner.name)
        message["taskName"] = str(task.name)
        message["unknown"] = 0
        message["dateTime"] = self.seconds_time
        message["removedColl"] = ""

        #Get the removed Collaborator using his mail
        for userObj.email in taskObj.collaborators:
            user = userbll.getUserByEmail(userObj)
            if not (user.name):
                message["unknown"] += 1
            else:
                message["removedColl"] += user.name + ", "
        return message
예제 #17
0
def remCollaborators(taskObj):
    """
	Remove collaborators from an existing task

	:type taskObj: object
	:param taskObj: An instance with the following attributes
					collaborators
	:return An instance of the Task class

	"""
    userObj = Collection()
    task = getTaskById(taskObj)
    for userObj.email in taskObj.collaborators:
        user = userbll.getUserByEmail(userObj)
        Task.objects(id=taskObj.id).update_one(pull__collaborators__user=user)
    task.save()
    task.reload()
    return task
예제 #18
0
def verifyEmail(email, key):
	"""
	Verify email of the user to confirm account

	route(/user/verifyEmail/<email>/<key>)
	"""
	userObj = Collection()
	userObj.email = email
	userObj.key = key
	try:
		flag = bll.verifyEmail(userObj)
		if flag is True:
			message = "Verification was Sucessful. Your account has been activiated"
		else:
			message = "Email and Key does not match or the key has expired. Please try again"
	except Exception as e:
		message = "Oops! The user doesnt seem to exist"
	return template("email_verified", message = message)
예제 #19
0
def createGroup():
    groupObj = Collection()
    response = {}
    data = {}
    obj = request.json
    try:
        groupObj.access_token = obj["access_token"]
        groupObj.owner = obj["owner_id"]
        groupObj.title = obj["title"]
        if checkAccessTokenValid(groupObj) is True:
            group = bll.createGroup(groupObj)
        data["group"] = bll.groupToDictConverter(group)
        response["status"] = RESPONSE_SUCCESS
        response["data"] = data
    except Exception as e:
        response["status"] = RESPONSE_FAILED
        response["message"] = str(e)
        if hasattr(e, "code"):
            response["code"] = e.code
    return response
예제 #20
0
def remGroupMembers(groupObj):
    """
	Remove memberd from a group

	:type groupObj : object
	:param groupObj : An instance of Collection with the following attributes
						id - id of the TaskGroup
						member - list of members to be added to the group
	:return : An instance of the Group class
	"""

    userObj = Collection()

    taskgroup = getGroupById(groupObj)
    for userObj.id in groupObj.members:
        user = userbll.getUserById(userObj)
        TaskGroup.objects(id=taskgroup.id).update_one(pull__members=user)
    taskgroup.save()
    taskgroup.reload()
    return taskgroup
예제 #21
0
def addCollaborators():
    taskObj = Collection()
    response = {}
    data = {}
    obj = request.json
    # try:
    taskObj.access_token = obj["access_token"]
    taskObj.id = obj["id"]
    taskObj.collaborators = obj["collaborators"]
    taskObj.group_id = obj["group_id"]
    if checkAccessTokenValid(taskObj) is True:
        task = bll.addCollaborators(taskObj)
    response["status"] = RESPONSE_SUCCESS
    response["data"] = bll.taskToDictConverter(task)
    # except Exception as e:
    # 	response["status"] = RESPONSE_FAILED
    # 	response["message"] = str(e)
    # 	if hasattr(e, "code"):
    # 		response["code"] = e.code
    return response
예제 #22
0
def doUpdatePassword():
	"""perform password update"""
	userObj = Collection()

	userObj.email = request.forms.get('email')
	userObj.password = request.forms.get('password')
	userObj.key = request.forms.get('key')
	try:
		userObj.user = bll.getUserByEmail(userObj)
		token = bll.getTokenByUser(userObj)
		if (userObj.key == token.key):
			flag = bll.updatePassword(userObj)
			if flag:
				message = "Password has been updated"
			else:
				message = "Password Update Failed. Please Try again"
		else:
			message = "Email and Key mismatch. Please try again"
	except Exception as e:
		message = "Oops! Something went wrong. Please try again"
	return template("updatePasswordResult", message = message)
예제 #23
0
def addNewTask():
    taskObj = Collection()
    response = {}
    data = {}
    obj = request.json
    try:
        taskObj.access_token = obj["access_token"]
        taskObj.owner = obj["owner"]
        taskObj.name = obj["name"]
        try:
            taskObj.priority = obj["priority"]
        except KeyError:
            taskObj.priority = 1
        try:
            taskObj.description = obj["description"]
        except KeyError:
            taskObj.description = ''
        try:
            taskObj.dueDateTime = obj["dueDateTime"]
        except KeyError:
            taskObj.dueDateTime = 0
        taskObj.collaborators = obj["collaborators"]
        taskObj.group_id = obj["group_id"]
        try:
            taskObj.collaborator_count = obj["collaborator_count"]
        except KeyError:
            taskObj.collaborator_count = 1
        #Validate access_token and continue process
        if checkAccessTokenValid(taskObj) is True:
            task = bll.addNewTask(taskObj)
        response["status"] = RESPONSE_SUCCESS
        response["data"] = bll.taskToDictConverter(task)
    except Exception as e:
        response["status"] = RESPONSE_FAILED
        response["message"] = str(e)
        if hasattr(e, "code"):
            response["code"] = e.code
    return response
예제 #24
0
def createGroup(groupObj):
    """

	Create a new group
	:type groupObj : object
	:param groupObj : An instance with the following attributes
						ownerId - userId of the creator/ member
						title - name of the groupObj
	:return group : An instance of the Group class
	"""

    userObj = Collection()
    members = []

    #for finding the user id of the owner
    userObj.id = groupObj.owner
    groupObj.user = userbll.getUserById(userObj)
    taskgroup = TaskGroup(owner=groupObj.user, title=groupObj.title)
    taskgroup.save()
    members.append(groupObj.user)
    TaskGroup.objects(id=taskgroup.id).update(push_all__members=members)
    taskgroup.reload()
    return taskgroup
예제 #25
0
def setServerPushId():
	"""
	Set the serverPushId for the particular user
	"""
	response = {}
	data = {}
	userObj = Collection()

	obj = request.json
	print obj
	try:
		userObj.access_token = obj["access_token"]
		userObj.id = obj["id"]
		userObj.serverPushId = obj["serverPushId"]
		if bll.checkAccessTokenValid(userObj):
			user = bll.setServerPushId(userObj)
		response["data"] = bll.convertUserToDict(user)
		response["status"] = RESPONSE_SUCCESS
	except Exception, e:
		response['status'] = RESPONSE_FAILED
		response['message'] = str(e)
		if hasattr(e, "code"):
			response["code"] = e.code
예제 #26
0
def editTask():
    taskObj = Collection()
    response = {}
    data = {}
    obj = request.json
    try:
        taskObj.access_token = obj["access_token"]
        taskObj.id = obj["id"]
        taskObj.priority = obj["priority"]
        taskObj.name = obj["name"]
        taskObj.description = obj["description"]
        taskObj.dueDateTime = obj["dueDateTime"]
        taskObj.collaborator_count = obj["collaborator_count"]
        taskObj["group_id"] = obj["group_id"]
        if checkAccessTokenValid(taskObj) is True:
            task = bll.editTask(taskObj)
        response["status"] = RESPONSE_SUCCESS
        response["data"] = bll.taskToDictConverter(task)
    except Exception as e:
        response["status"] = RESPONSE_FAILED
        response["message"] = str(e)
        if hasattr(e, "code"):
            response["code"] = e.code
    return response
예제 #27
0
def sendVerification(user):
    """
	Send verification mail to the user and proide confirmation link for verification

	::type userObj: object
	::param userObj: instance of User class with the following attributes
					email - email id of the user
					name - name of the user
					**kwargs
	"""
    userObj = Collection()
    userObj.user = user
    token = dal.getTokenByUser(userObj)
    userObj.key = token.refresh_token

    link = """http://taskie.me/user/verifyEmail/%s/%s""" % (userObj.user.email,
                                                            userObj.key)
    delete = """http://taskie.me/user/deleteAccount/%s/%s""" % (
        userObj.user.email, userObj.key)
    html = '''\
    <style type="text/css">
	body {
	  margin: 0;
	  mso-line-height-rule: exactly;
	  padding: 0;
	  min-width: 100%%;
	}
	table {
	  border-collapse: collapse;
	  border-spacing: 0;
	}
	td {
	  padding: 0;
	  vertical-align: top;
	}
	.spacer,
	.border {
	  font-size: 1px;
	  line-height: 1px;
	}
	.spacer {
	  width: 100%%;
	}
	img {
	  border: 0;
	  -ms-interpolation-mode: bicubic;
	}
	.image {
	  font-size: 12px;
	  Margin-bottom: 24px;
	  mso-line-height-rule: at-least;
	}
	.image img {
	  display: block;
	}
	.logo {
	  mso-line-height-rule: at-least;
	}
	.logo img {
	  display: block;
	}
	strong {
	  font-weight: bold;
	}
	h1,
	h2,
	h3,
	p,
	ol,
	ul,
	li {
	  Margin-top: 0;
	}
	ol,
	ul,
	li {
	  padding-left: 0;
	}
	blockquote {
	  Margin-top: 0;
	  Margin-right: 0;
	  Margin-bottom: 0;
	  padding-right: 0;
	}
	.column-top {
	  font-size: 32px;
	  line-height: 32px;
	}
	.column-bottom {
	  font-size: 8px;
	  line-height: 8px;
	}
	.column {
	  text-align: left;
	}
	.contents {
	  table-layout: fixed;
	  width: 100%%;
	}
	.padded {
	  padding-left: 32px;
	  padding-right: 32px;
	  word-break: break-word;
	  word-wrap: break-word;
	}
	.wrapper {
	  display: table;
	  table-layout: fixed;
	  width: 100%%;
	  min-width: 620px;
	  -webkit-text-size-adjust: 100%%;
	  -ms-text-size-adjust: 100%%;
	}
	table.wrapper {
	  table-layout: fixed;
	}
	.one-col,
	.two-col,
	.three-col {
	  Margin-left: auto;
	  Margin-right: auto;
	  width: 600px;
	}
	.centered {
	  Margin-left: auto;
	  Margin-right: auto;
	}
	.two-col .image {
	  Margin-bottom: 23px;
	}
	.two-col .column-bottom {
	  font-size: 9px;
	  line-height: 9px;
	}
	.two-col .column {
	  width: 300px;
	}
	.three-col .image {
	  Margin-bottom: 21px;
	}
	.three-col .column-bottom {
	  font-size: 11px;
	  line-height: 11px;
	}
	.three-col .column {
	  width: 200px;
	}
	.three-col .first .padded {
	  padding-left: 32px;
	  padding-right: 16px;
	}
	.three-col .second .padded {
	  padding-left: 24px;
	  padding-right: 24px;
	}
	.three-col .third .padded {
	  padding-left: 16px;
	  padding-right: 32px;
	}
	@media only screen and (min-width: 0) {
	  .wrapper {
	    text-rendering: optimizeLegibility;
	  }
	}
	@media only screen and (max-width: 620px) {
	  [class=wrapper] {
	    min-width: 318px !important;
	    width: 100%% !important;
	  }
	  [class=wrapper] .one-col,
	  [class=wrapper] .two-col,
	  [class=wrapper] .three-col {
	    width: 318px !important;
	  }
	  [class=wrapper] .column,
	  [class=wrapper] .gutter {
	    display: block;
	    float: left;
	    width: 318px !important;
	  }
	  [class=wrapper] .padded {
	    padding-left: 32px !important;
	    padding-right: 32px !important;
	  }
	  [class=wrapper] .block {
	    display: block !important;
	  }
	  [class=wrapper] .hide {
	    display: none !important;
	  }
	  [class=wrapper] .image {
	    margin-bottom: 24px !important;
	  }
	  [class=wrapper] .image img {
	    height: auto !important;
	    width: 100%% !important;
	  }
	}
	.wrapper h1 {
	  font-weight: 700;
	}
	.wrapper h2 {
	  font-style: italic;
	  font-weight: normal;
	}
	.wrapper h3 {
	  font-weight: normal;
	}
	.one-col blockquote,
	.two-col blockquote,
	.three-col blockquote {
	  font-style: italic;
	}
	.one-col-feature h1 {
	  font-weight: normal;
	}
	.one-col-feature h2 {
	  font-style: normal;
	  font-weight: bold;
	}
	.one-col-feature h3 {
	  font-style: italic;
	}
	td.border {
	  width: 1px;
	}
	tr.border {
	  background-color: #e9e9e9;
	  height: 1px;
	}
	tr.border td {
	  line-height: 1px;
	}
	.one-col,
	.two-col,
	.three-col,
	.one-col-feature {
	  background-color: #ffffff;
	  font-size: 14px;
	  table-layout: fixed;
	}
	.one-col,
	.two-col,
	.three-col,
	.one-col-feature,
	.preheader,
	.header,
	.footer {
	  Margin-left: auto;
	  Margin-right: auto;
	}
	.preheader table {
	  width: 602px;
	}
	.preheader .title,
	.preheader .webversion {
	  padding-top: 10px;
	  padding-bottom: 12px;
	  font-size: 12px;
	  line-height: 21px;
	}
	.preheader .title {
	  text-align: left;
	}
	.preheader .webversion {
	  text-align: right;
	  width: 300px;
	}
	.header {
	  width: 602px;
	}
	.header .logo {
	  padding: 32px 0;
	}
	.header .logo div {
	  font-size: 26px;
	  font-weight: 700;
	  letter-spacing: -0.02em;
	  line-height: 32px;
	}
	.header .logo div a {
	  text-decoration: none;
	}
	.header .logo div.logo-center {
	  text-align: center;
	}
	.header .logo div.logo-center img {
	  Margin-left: auto;
	  Margin-right: auto;
	}
	.gmail {
	  width: 650px;
	  min-width: 650px;
	}
	.gmail td {
	  font-size: 1px;
	  line-height: 1px;
	}
	.wrapper a {
	  text-decoration: underline;
	  transition: all .2s;
	}
	.wrapper h1 {
	  font-size: 36px;
	  Margin-bottom: 18px;
	}
	.wrapper h2 {
	  font-size: 26px;
	  line-height: 32px;
	  Margin-bottom: 20px;
	}
	.wrapper h3 {
	  font-size: 18px;
	  line-height: 22px;
	  Margin-bottom: 16px;
	}
	.wrapper h1 a,
	.wrapper h2 a,
	.wrapper h3 a {
	  text-decoration: none;
	}
	.one-col blockquote,
	.two-col blockquote,
	.three-col blockquote {
	  font-size: 14px;
	  border-left: 2px solid #e9e9e9;
	  Margin-left: 0;
	  padding-left: 16px;
	}
	table.divider {
	  width: 100%%;
	}
	.divider .inner {
	  padding-bottom: 24px;
	}
	.divider table {
	  background-color: #e9e9e9;
	  font-size: 2px;
	  line-height: 2px;
	  width: 60px;
	}
	.wrapper .gray {
	  background-color: #f7f7f7;
	}
	.wrapper .gray blockquote {
	  border-left-color: #dddddd;
	}
	.wrapper .gray .divider table {
	  background-color: #dddddd;
	}
	.padded .image {
	  font-size: 0;
	}
	.image-frame {
	  padding: 8px;
	}
	.image-background {
	  display: inline-block;
	  font-size: 12px;
	}
	.btn {
	  Margin-bottom: 24px;
	  padding: 2px;
	}
	.btn a {
	  border: 1px solid #ffffff;
	  display: inline-block;
	  font-size: 13px;
	  font-weight: bold;
	  line-height: 15px;
	  outline-style: solid;
	  outline-width: 2px;
	  padding: 10px 30px;
	  text-align: center;
	  text-decoration: none !important;
	}
	.one-col .column table:nth-last-child(2) td h1:last-child,
	.one-col .column table:nth-last-child(2) td h2:last-child,
	.one-col .column table:nth-last-child(2) td h3:last-child,
	.one-col .column table:nth-last-child(2) td p:last-child,
	.one-col .column table:nth-last-child(2) td ol:last-child,
	.one-col .column table:nth-last-child(2) td ul:last-child {
	  Margin-bottom: 24px;
	}
	.one-col p,
	.one-col ol,
	.one-col ul {
	  font-size: 16px;
	  line-height: 24px;
	}
	.one-col ol,
	.one-col ul {
	  Margin-left: 18px;
	}
	.two-col .column table:nth-last-child(2) td h1:last-child,
	.two-col .column table:nth-last-child(2) td h2:last-child,
	.two-col .column table:nth-last-child(2) td h3:last-child,
	.two-col .column table:nth-last-child(2) td p:last-child,
	.two-col .column table:nth-last-child(2) td ol:last-child,
	.two-col .column table:nth-last-child(2) td ul:last-child {
	  Margin-bottom: 23px;
	}
	.two-col .image-frame {
	  padding: 6px;
	}
	.two-col h1 {
	  font-size: 26px;
	  line-height: 32px;
	  Margin-bottom: 16px;
	}
	.two-col h2 {
	  font-size: 20px;
	  line-height: 26px;
	  Margin-bottom: 18px;
	}
	.two-col h3 {
	  font-size: 16px;
	  line-height: 20px;
	  Margin-bottom: 14px;
	}
	.two-col p,
	.two-col ol,
	.two-col ul {
	  font-size: 14px;
	  line-height: 23px;
	}
	.two-col ol,
	.two-col ul {
	  Margin-left: 16px;
	}
	.two-col li {
	  padding-left: 5px;
	}
	.two-col .divider .inner {
	  padding-bottom: 23px;
	}
	.two-col .btn {
	  Margin-bottom: 23px;
	}
	.two-col blockquote {
	  padding-left: 16px;
	}
	.three-col .column table:nth-last-child(2) td h1:last-child,
	.three-col .column table:nth-last-child(2) td h2:last-child,
	.three-col .column table:nth-last-child(2) td h3:last-child,
	.three-col .column table:nth-last-child(2) td p:last-child,
	.three-col .column table:nth-last-child(2) td ol:last-child,
	.three-col .column table:nth-last-child(2) td ul:last-child {
	  Margin-bottom: 21px;
	}
	.three-col .image-frame {
	  padding: 4px;
	}
	.three-col h1 {
	  font-size: 20px;
	  line-height: 26px;
	  Margin-bottom: 12px;
	}
	.three-col h2 {
	  font-size: 16px;
	  line-height: 22px;
	  Margin-bottom: 14px;
	}
	.three-col h3 {
	  font-size: 14px;
	  line-height: 18px;
	  Margin-bottom: 10px;
	}
	.three-col p,
	.three-col ol,
	.three-col ul {
	  font-size: 12px;
	  line-height: 21px;
	}
	.three-col ol,
	.three-col ul {
	  Margin-left: 14px;
	}
	.three-col li {
	  padding-left: 6px;
	}
	.three-col .divider .inner {
	  padding-bottom: 21px;
	}
	.three-col .btn {
	  Margin-bottom: 21px;
	}
	.three-col .btn a {
	  font-size: 12px;
	  line-height: 14px;
	  padding: 8px 19px;
	}
	.three-col blockquote {
	  padding-left: 16px;
	}
	.one-col-feature .column-top {
	  font-size: 36px;
	  line-height: 36px;
	}
	.one-col-feature .column-bottom {
	  font-size: 4px;
	  line-height: 4px;
	}
	.one-col-feature .column {
	  text-align: center;
	  width: 600px;
	}
	.one-col-feature .image {
	  Margin-bottom: 32px;
	}
	.one-col-feature .column table:nth-last-child(2) td h1:last-child,
	.one-col-feature .column table:nth-last-child(2) td h2:last-child,
	.one-col-feature .column table:nth-last-child(2) td h3:last-child,
	.one-col-feature .column table:nth-last-child(2) td p:last-child,
	.one-col-feature .column table:nth-last-child(2) td ol:last-child,
	.one-col-feature .column table:nth-last-child(2) td ul:last-child {
	  Margin-bottom: 32px;
	}
	.one-col-feature h1,
	.one-col-feature h2,
	.one-col-feature h3 {
	  text-align: center;
	}
	.one-col-feature h1 {
	  font-size: 52px;
	  Margin-bottom: 22px;
	}
	.one-col-feature h2 {
	  font-size: 42px;
	  Margin-bottom: 20px;
	}
	.one-col-feature h3 {
	  font-size: 32px;
	  line-height: 42px;
	  Margin-bottom: 20px;
	}
	.one-col-feature p,
	.one-col-feature ol,
	.one-col-feature ul {
	  font-size: 21px;
	  line-height: 32px;
	  Margin-bottom: 32px;
	}
	.one-col-feature p a,
	.one-col-feature ol a,
	.one-col-feature ul a {
	  text-decoration: none;
	}
	.one-col-feature p {
	  text-align: center;
	}
	.one-col-feature ol,
	.one-col-feature ul {
	  Margin-left: 40px;
	  text-align: left;
	}
	.one-col-feature li {
	  padding-left: 3px;
	}
	.one-col-feature .btn {
	  Margin-bottom: 32px;
	  text-align: center;
	}
	.one-col-feature .divider .inner {
	  padding-bottom: 32px;
	}
	.one-col-feature blockquote {
	  border-bottom: 2px solid #e9e9e9;
	  border-left-color: #ffffff;
	  border-left-width: 0;
	  border-left-style: none;
	  border-top: 2px solid #e9e9e9;
	  Margin-bottom: 32px;
	  Margin-left: 0;
	  padding-bottom: 42px;
	  padding-left: 0;
	  padding-top: 42px;
	  position: relative;
	}
	.one-col-feature blockquote:before,
	.one-col-feature blockquote:after {
	  background: -moz-linear-gradient(left, #ffffff 25%%, #e9e9e9 25%%, #e9e9e9 75%%, #ffffff 75%%);
	  background: -webkit-gradient(linear, left top, right top, color-stop(25%%, #ffffff), color-stop(25%%, #e9e9e9), color-stop(75%%, #e9e9e9), color-stop(75%%, #ffffff));
	  background: -webkit-linear-gradient(left, #ffffff 25%%, #e9e9e9 25%%, #e9e9e9 75%%, #ffffff 75%%);
	  background: -o-linear-gradient(left, #ffffff 25%%, #e9e9e9 25%%, #e9e9e9 75%%, #ffffff 75%%);
	  background: -ms-linear-gradient(left, #ffffff 25%%, #e9e9e9 25%%, #e9e9e9 75%%, #ffffff 75%%);
	  background: linear-gradient(to right, #ffffff 25%%, #e9e9e9 25%%, #e9e9e9 75%%, #ffffff 75%%);
	  content: '';
	  display: block;
	  height: 2px;
	  left: 0;
	  outline: 1px solid #ffffff;
	  position: absolute;
	  right: 0;
	}
	.one-col-feature blockquote:before {
	  top: -2px;
	}
	.one-col-feature blockquote:after {
	  bottom: -2px;
	}
	.one-col-feature blockquote p,
	.one-col-feature blockquote ol,
	.one-col-feature blockquote ul {
	  font-size: 42px;
	  line-height: 48px;
	  Margin-bottom: 48px;
	}
	.one-col-feature blockquote p:last-child,
	.one-col-feature blockquote ol:last-child,
	.one-col-feature blockquote ul:last-child {
	  Margin-bottom: 0 !important;
	}
	.footer {
	  width: 602px;
	}
	.footer .padded {
	  font-size: 12px;
	  line-height: 20px;
	}
	.social {
	  padding-top: 32px;
	  padding-bottom: 22px;
	}
	.social img {
	  display: block;
	}
	.social .divider {
	  font-family: sans-serif;
	  font-size: 10px;
	  line-height: 21px;
	  text-align: center;
	  padding-left: 14px;
	  padding-right: 14px;
	}
	.social .social-text {
	  height: 21px;
	  vertical-align: middle !important;
	  font-size: 10px;
	  font-weight: bold;
	  text-decoration: none;
	  text-transform: uppercase;
	}
	.social .social-text a {
	  text-decoration: none;
	}
	.address {
	  width: 250px;
	}
	.address .padded {
	  text-align: left;
	  padding-left: 0;
	  padding-right: 10px;
	}
	.subscription {
	  width: 350px;
	}
	.subscription .padded {
	  text-align: right;
	  padding-right: 0;
	  padding-left: 10px;
	}
	.address,
	.subscription {
	  padding-top: 32px;
	  padding-bottom: 64px;
	}
	.address a,
	.subscription a {
	  font-weight: bold;
	  text-decoration: none;
	}
	.address table,
	.subscription table {
	  width: 100%%;
	}
	@media only screen and (max-width: 651px) {
	  .gmail {
	    display: none !important;
	  }
	}
	@media only screen and (max-width: 620px) {
	  [class=wrapper] .one-col .column:last-child table:nth-last-child(2) td h1:last-child,
	  [class=wrapper] .two-col .column:last-child table:nth-last-child(2) td h1:last-child,
	  [class=wrapper] .three-col .column:last-child table:nth-last-child(2) td h1:last-child,
	  [class=wrapper] .one-col-feature .column:last-child table:nth-last-child(2) td h1:last-child,
	  [class=wrapper] .one-col .column:last-child table:nth-last-child(2) td h2:last-child,
	  [class=wrapper] .two-col .column:last-child table:nth-last-child(2) td h2:last-child,
	  [class=wrapper] .three-col .column:last-child table:nth-last-child(2) td h2:last-child,
	  [class=wrapper] .one-col-feature .column:last-child table:nth-last-child(2) td h2:last-child,
	  [class=wrapper] .one-col .column:last-child table:nth-last-child(2) td h3:last-child,
	  [class=wrapper] .two-col .column:last-child table:nth-last-child(2) td h3:last-child,
	  [class=wrapper] .three-col .column:last-child table:nth-last-child(2) td h3:last-child,
	  [class=wrapper] .one-col-feature .column:last-child table:nth-last-child(2) td h3:last-child,
	  [class=wrapper] .one-col .column:last-child table:nth-last-child(2) td p:last-child,
	  [class=wrapper] .two-col .column:last-child table:nth-last-child(2) td p:last-child,
	  [class=wrapper] .three-col .column:last-child table:nth-last-child(2) td p:last-child,
	  [class=wrapper] .one-col-feature .column:last-child table:nth-last-child(2) td p:last-child,
	  [class=wrapper] .one-col .column:last-child table:nth-last-child(2) td ol:last-child,
	  [class=wrapper] .two-col .column:last-child table:nth-last-child(2) td ol:last-child,
	  [class=wrapper] .three-col .column:last-child table:nth-last-child(2) td ol:last-child,
	  [class=wrapper] .one-col-feature .column:last-child table:nth-last-child(2) td ol:last-child,
	  [class=wrapper] .one-col .column:last-child table:nth-last-child(2) td ul:last-child,
	  [class=wrapper] .two-col .column:last-child table:nth-last-child(2) td ul:last-child,
	  [class=wrapper] .three-col .column:last-child table:nth-last-child(2) td ul:last-child,
	  [class=wrapper] .one-col-feature .column:last-child table:nth-last-child(2) td ul:last-child {
	    Margin-bottom: 24px !important;
	  }
	  [class=wrapper] .address,
	  [class=wrapper] .subscription {
	    display: block;
	    float: left;
	    width: 318px !important;
	    text-align: center !important;
	  }
	  [class=wrapper] .address {
	    padding-bottom: 0 !important;
	  }
	  [class=wrapper] .subscription {
	    padding-top: 0 !important;
	  }
	  [class=wrapper] h1 {
	    font-size: 36px !important;
	    line-height: 42px !important;
	    Margin-bottom: 18px !important;
	  }
	  [class=wrapper] h2 {
	    font-size: 26px !important;
	    line-height: 32px !important;
	    Margin-bottom: 20px !important;
	  }
	  [class=wrapper] h3 {
	    font-size: 18px !important;
	    line-height: 22px !important;
	    Margin-bottom: 16px !important;
	  }
	  [class=wrapper] p,
	  [class=wrapper] ol,
	  [class=wrapper] ul {
	    font-size: 16px !important;
	    line-height: 24px !important;
	    Margin-bottom: 24px !important;
	  }
	  [class=wrapper] ol,
	  [class=wrapper] ul {
	    Margin-left: 18px !important;
	  }
	  [class=wrapper] li {
	    padding-left: 2px !important;
	  }
	  [class=wrapper] blockquote {
	    padding-left: 16px !important;
	  }
	  [class=wrapper] .two-col .column:nth-child(n + 3) {
	    border-top: 1px solid #e9e9e9;
	  }
	  [class=wrapper] .btn {
	    margin-bottom: 24px !important;
	  }
	  [class=wrapper] .btn a {
	    display: block !important;
	    font-size: 13px !important;
	    font-weight: bold !important;
	    line-height: 15px !important;
	    padding: 10px 30px !important;
	  }
	  [class=wrapper] .column-bottom {
	    font-size: 8px !important;
	    line-height: 8px !important;
	  }
	  [class=wrapper] .first .column-bottom,
	  [class=wrapper] .three-col .second .column-bottom {
	    display: none;
	  }
	  [class=wrapper] .second .column-top,
	  [class=wrapper] .third .column-top {
	    display: none;
	  }
	  [class=wrapper] .image-frame {
	    padding: 4px !important;
	  }
	  [class=wrapper] .header .logo {
	    padding-left: 10px !important;
	    padding-right: 10px !important;
	  }
	  [class=wrapper] .header .logo div {
	    font-size: 26px !important;
	    line-height: 32px !important;
	  }
	  [class=wrapper] .header .logo div img {
	    display: inline-block !important;
	    max-width: 280px !important;
	    height: auto !important;
	  }
	  [class=wrapper] table.border,
	  [class=wrapper] .header,
	  [class=wrapper] .webversion,
	  [class=wrapper] .footer {
	    width: 320px !important;
	  }
	  [class=wrapper] .preheader .webversion,
	  [class=wrapper] .header .logo a {
	    text-align: center !important;
	  }
	  [class=wrapper] .preheader table,
	  [class=wrapper] .border td {
	    width: 318px !important;
	  }
	  [class=wrapper] .border td.border {
	    width: 1px !important;
	  }
	  [class=wrapper] .image .border td {
	    width: auto !important;
	  }
	  [class=wrapper] .title {
	    display: none;
	  }
	  [class=wrapper] .footer .padded {
	    text-align: center !important;
	  }
	  [class=wrapper] .footer .subscription .padded {
	    padding-top: 20px !important;
	  }
	  [class=wrapper] .footer .social-link {
	    display: block !important;
	  }
	  [class=wrapper] .footer .social-link table {
	    margin: 0 auto 10px !important;
	  }
	  [class=wrapper] .footer .divider {
	    display: none !important;
	  }
	  [class=wrapper] .one-col-feature .btn {
	    margin-bottom: 28px !important;
	  }
	  [class=wrapper] .one-col-feature .image {
	    margin-bottom: 28px !important;
	  }
	  [class=wrapper] .one-col-feature .divider .inner {
	    padding-bottom: 28px !important;
	  }
	  [class=wrapper] .one-col-feature h1 {
	    font-size: 42px !important;
	    line-height: 48px !important;
	    margin-bottom: 20px !important;
	  }
	  [class=wrapper] .one-col-feature h2 {
	    font-size: 32px !important;
	    line-height: 36px !important;
	    margin-bottom: 18px !important;
	  }
	  [class=wrapper] .one-col-feature h3 {
	    font-size: 26px !important;
	    line-height: 32px !important;
	    margin-bottom: 20px !important;
	  }
	  [class=wrapper] .one-col-feature p,
	  [class=wrapper] .one-col-feature ol,
	  [class=wrapper] .one-col-feature ul {
	    font-size: 20px !important;
	    line-height: 28px !important;
	    margin-bottom: 28px !important;
	  }
	  [class=wrapper] .one-col-feature blockquote {
	    font-size: 18px !important;
	    line-height: 26px !important;
	    margin-bottom: 28px !important;
	    padding-bottom: 26px !important;
	    padding-left: 0 !important;
	    padding-top: 26px !important;
	  }
	  [class=wrapper] .one-col-feature blockquote p,
	  [class=wrapper] .one-col-feature blockquote ol,
	  [class=wrapper] .one-col-feature blockquote ul {
	    font-size: 26px !important;
	    line-height: 32px !important;
	  }
	  [class=wrapper] .one-col-feature blockquote p:last-child,
	  [class=wrapper] .one-col-feature blockquote ol:last-child,
	  [class=wrapper] .one-col-feature blockquote ul:last-child {
	    margin-bottom: 0 !important;
	  }
	  [class=wrapper] .one-col-feature .column table:last-of-type h1:last-child,
	  [class=wrapper] .one-col-feature .column table:last-of-type h2:last-child,
	  [class=wrapper] .one-col-feature .column table:last-of-type h3:last-child {
	    margin-bottom: 28px !important;
	  }
	}
	@media only screen and (max-width: 320px) {
	  [class=wrapper] td.border {
	    display: none;
	  }
	  [class=wrapper] table.border,
	  [class=wrapper] .header,
	  [class=wrapper] .webversion,
	  [class=wrapper] .footer {
	    width: 318px !important;
	  }
	}
	</style>
	    <!--[if gte mso 9]>
	    <style>
	      .column-top {
	        mso-line-height-rule: exactly !important;
	      }
	    </style>
	    <![endif]-->
	  <meta name="robots" content="noindex,nofollow"></meta>
	<meta property="og:title" content="My First Campaign"></meta>
	<link href="http://css.createsend1.com/css/social.min.css?h=A3DB20FCbananabread" media="screen,projection" rel="stylesheet" type="text/css" />
	</head>
	  <body style="margin: 0;mso-line-height-rule: exactly;padding: 0;min-width: 100%%;background-color: #fbfbfb"><style type="text/css">
	body,.wrapper,.emb-editor-canvas{background-color:#fbfbfb}.border{background-color:#e9e9e9}h1{color:#d81b60}.wrapper h1{}.wrapper h1{font-family:sans-serif}@media only screen and (min-width: 0){.wrapper h1{font-family:Avenir,sans-serif !important}}h1{}.one-col h1{line-height:42px}.two-col h1{line-height:32px}.three-col h1{line-height:26px}.wrapper .one-col-feature h1{line-height:58px}@media only screen and (max-width: 620px){h1{line-height:42px !important}}h2{color:#555}.wrapper h2{}.wrapper h2{font-family:Georgia,serif}h2{}.one-col h2{line-height:32px}.two-col h2{line-height:26px}.three-col h2{line-height:22px}.wrapper .one-col-feature h2{line-height:52px}@media only screen and (max-width: 620px){h2{line-height:32px !important}}h3{color:#555}.wrapper h3{}.wrapper h3{font-family:Georgia,serif}h3{}.one-col h3{line-height:26px}.two-col h3{line-height:22px}.three-col 
	h3{line-height:20px}.wrapper .one-col-feature h3{line-height:42px}@media only screen and (max-width: 620px){h3{line-height:26px !important}}p,ol,ul{color:#565656}.wrapper p,.wrapper ol,.wrapper ul{}.wrapper p,.wrapper ol,.wrapper ul{font-family:Georgia,serif}p,ol,ul{}.one-col p,.one-col ol,.one-col ul{line-height:25px;Margin-bottom:25px}.two-col p,.two-col ol,.two-col ul{line-height:23px;Margin-bottom:23px}.three-col p,.three-col ol,.three-col ul{line-height:21px;Margin-bottom:21px}.wrapper .one-col-feature p,.wrapper .one-col-feature ol,.wrapper .one-col-feature ul{line-height:32px}.one-col-feature blockquote p,.one-col-feature blockquote ol,.one-col-feature blockquote ul{line-height:50px}@media only screen and (max-width: 620px){p,ol,ul{line-height:25px !important;Margin-bottom:25px !important}}.image{color:#565656}.image{font-family:Georgia,serif}.wrapper a{color:#41637e}.wrapper 
	a:hover{color:#30495c !important}.wrapper .logo div{color:#41637e}.wrapper .logo div{font-family:sans-serif}@media only screen and (min-width: 0){.wrapper .logo div{font-family:Avenir,sans-serif !important}}.wrapper .logo div a{color:#41637e}.wrapper .logo div a:hover{color:#41637e !important}.wrapper .one-col-feature p a,.wrapper .one-col-feature ol a,.wrapper .one-col-feature ul a{border-bottom:1px solid #41637e}.wrapper .one-col-feature p a:hover,.wrapper .one-col-feature ol a:hover,.wrapper .one-col-feature ul a:hover{color:#30495c !important;border-bottom:1px solid #30495c !important}.btn a{}.wrapper .btn a{}.wrapper .btn a{font-family:Georgia,serif}.wrapper .btn a{background-color:#d81b60;color:#fff !important;outline-color:#d81b60;text-shadow:0 1px 0 #c21856}.wrapper .btn a:hover{background-color:#c21856 !important;color:#fff !important;outline-color:#c21856 !important}.preheader 
	.title,.preheader .webversion,.footer .padded{color:#999}.preheader .title,.preheader .webversion,.footer .padded{font-family:Georgia,serif}.preheader .title a,.preheader .webversion a,.footer .padded a{color:#999}.preheader .title a:hover,.preheader .webversion a:hover,.footer .padded a:hover{color:#737373 !important}.footer .social .divider{color:#e9e9e9}.footer .social .social-text,.footer .social a{color:#999}.wrapper .footer .social .social-text,.wrapper .footer .social a{}.wrapper .footer .social .social-text,.wrapper .footer .social a{font-family:Georgia,serif}.footer .social .social-text,.footer .social a{}.footer .social .social-text,.footer .social a{letter-spacing:0.05em}.footer .social .social-text:hover,.footer .social a:hover{color:#737373 !important}.image .border{background-color:#c8c8c8}.image-frame{background-color:#dadada}.image-background{background-color:#f7f7f7}
	</style>
	    <center class="wrapper" style="display: table;table-layout: fixed;width: 100%%;min-width: 620px;-webkit-text-size-adjust: 100%%;-ms-text-size-adjust: 100%%;background-color: #fbfbfb">
	    	<table class="gmail" style="border-collapse: collapse;border-spacing: 0;width: 650px;min-width: 650px"><tbody><tr><td style="padding: 0;vertical-align: top;font-size: 1px;line-height: 1px">&nbsp;</td></tr></tbody></table>
	      <table class="preheader centered" style="border-collapse: collapse;border-spacing: 0;Margin-left: auto;Margin-right: auto">
	        <tbody><tr>
	          <td style="padding: 0;vertical-align: top">
	            <table style="border-collapse: collapse;border-spacing: 0;width: 602px">
	              <tbody><tr>
	                <td class="title" style="padding: 0;vertical-align: top;padding-top: 10px;padding-bottom: 12px;font-size: 12px;line-height: 21px;text-align: left;color: #999;font-family: Georgia,serif">Taskie Account Verification</td>
	                <td class="webversion" style="padding: 0;vertical-align: top;padding-top: 10px;padding-bottom: 12px;font-size: 12px;line-height: 21px;text-align: right;width: 300px;color: #999;font-family: Georgia,serif">
	                  No Images? <a style="text-decoration: none;transition: all .2s;color: #999;font-weight: bold" href="http://preview15060802.createsend1.com/t/i-e-jrhljhl-l-r/">Click here</a>
	                </td>
	              </tr>
	            </tbody></table>
	          </td>
	        </tr>
	      </tbody></table>
	      <table class="header centered" style="border-collapse: collapse;border-spacing: 0;Margin-left: auto;Margin-right: auto;width: 602px">
	        <tbody><tr><td class="border" style="padding: 0;vertical-align: top;font-size: 1px;line-height: 1px;background-color: #e9e9e9;width: 1px">&nbsp;</td></tr>
	        <tr><td class="logo" style="padding: 32px 0;vertical-align: top;mso-line-height-rule: at-least"><div class="logo-left" style="font-size: 26px;font-weight: 700;letter-spacing: -0.02em;line-height: 32px;color: #41637e;font-family: sans-serif" align="left" id="emb-email-header"><a style="text-decoration: none;transition: all .2s;color: #41637e" href="http://www.taskie.me/"><img style="border: 0;-ms-interpolation-mode: bicubic;display: block;max-width: 217px" src="http://i1.createsend1.com/ei/i/8C/5B5/29A/005229/csfinal/logo1.png" alt="Taskie.me" width="217" height="59"></a></div></td></tr>
	      </tbody></table>
	      
	          <table class="border" style="border-collapse: collapse;border-spacing: 0;font-size: 1px;line-height: 1px;background-color: #e9e9e9;Margin-left: auto;Margin-right: auto" width="602">
	            <tbody><tr><td style="padding: 0;vertical-align: top">&#8203;</td></tr>
	          </tbody></table>
	        
	          <table class="centered" style="border-collapse: collapse;border-spacing: 0;Margin-left: auto;Margin-right: auto">
	            <tbody><tr>
	              <td class="border" style="padding: 0;vertical-align: top;font-size: 1px;line-height: 1px;background-color: #e9e9e9;width: 1px">&#8203;</td>
	              <td style="padding: 0;vertical-align: top">
	                <table class="one-col" style="border-collapse: collapse;border-spacing: 0;Margin-left: auto;Margin-right: auto;width: 600px;background-color: #ffffff;font-size: 14px;table-layout: fixed">
	                  <tbody><tr>
	                    <td class="column" style="padding: 0;vertical-align: top;text-align: left">
	                      <div><div class="column-top" style="font-size: 32px;line-height: 32px">&nbsp;</div></div>
	                        <table class="contents" style="border-collapse: collapse;border-spacing: 0;table-layout: fixed;width: 100%%">
	                          <tbody><tr>
	                            <td class="padded" style="padding: 0;vertical-align: top;padding-left: 32px;padding-right: 32px;word-break: break-word;word-wrap: break-word">
	                              
	            
	<h1 style="Margin-top: 0;color: #d81b60;font-weight: 700;font-size: 36px;Margin-bottom: 18px;font-family: sans-serif;line-height: 42px">Hi %s,</h1><p style="Margin-top: 0;color: #565656;font-family: Georgia,serif;font-size: 16px;line-height: 25px;Margin-bottom: 25px">Greetings from Taskie,</p><p style="Margin-top: 0;color: #565656;font-family: Georgia,serif;font-size: 16px;line-height: 25px;Margin-bottom: 25px">Thanks for creating a Taskie account and being a part of our services. You are now just one step away from the Taskie experience.</p><p style="Margin-top: 0;color: #565656;font-family: Georgia,serif;font-size: 16px;line-height: 25px;Margin-bottom: 25px">As part of our security policy, we are required to verify the email id of every user registering to our service before their account is activated. Please visit the link below to activate your account and start using 
	Taskie.</p>

	<div class="btn" style="Margin-bottom: 24px;padding: 2px;text-align: center">
	              <![if !mso]><a style="display: inline-block;font-size: 13px;font-weight: bold;line-height: 15px; padding: 10px 30px;text-align: center;text-decoration: none !important;transition: all .2s;color: #fff !important;font-family: Georgia,serif;background-color: #d81b60;text-shadow: 0 1px 0 #c21856" href='%s'>ACTIVATE TASKIE ACCOUNT</a><![endif]>
	            <!--[if mso]><v:rect xmlns:v="urn:schemas-microsoft-com:vml" href="http://www.taskie.com" style="width:236px" fillcolor="#D81B60" strokecolor="#D81B60" strokeweight="6px"><v:stroke linestyle="thinthin"></v:stroke><v:textbox style="mso-fit-shape-to-text:t" inset="0px,7px,0px,7px"><center style="font-size:13px;line-height:15px;color:#FFFFFF;font-family:Georgia,serif;font-weight:bold;mso-line-height-rule:exactly;mso-text-raise:0px">Activate Taskie Account</center></v:textbox></v:rect><![endif]--></div>

	<p style="Margin-top: 0;color: #565656;font-family: Georgia,serif;font-size: 16px;line-height: 25px;Margin-bottom: 25px">If the account wasn't created by you, please delete the account by clicking the following link</p><a href="%s">Click Here to Deactivate Taskie</a><p style="Margin-top: 0;color: #565656;font-family: Georgia,serif;font-size: 16px;line-height: 25px;Margin-bottom: 25px">Failing to do so may prevent you from creating a Taskie account using this email id in future.</p><p style="Margin-top: 0;color: #565656;font-family: Georgia,serif;font-size: 16px;line-height: 25px;Margin-bottom: 25px">For more information and support, please feel free to send us an email at [email protected]. Our support team will be getting back to you within 24 Hrs</p><p style="Margin-top: 0;color: #565656;font-family: Georgia,serif;font-size: 16px;line-height: 25px;Margin-bottom: 25px">Thanks and Warm Regards,</p><p style="Margin-top: 
	0;color: #565656;font-family: Georgia,serif;font-size: 16px;line-height: 25px;Margin-bottom: 25px">Team Taskie</p>
	          
	                            </td>
	                          </tr>
	                        </tbody>
	                      </table>
	                    </td>
	                  </tr>
	                </tbody></table>
	              </td>
	              <td class="border" style="padding: 0;vertical-align: top;font-size: 1px;line-height: 1px;background-color: #e9e9e9;width: 1px">&#8203;</td>
	            </tr>
	          </tbody></table>
	        
	          <table class="border" style="border-collapse: collapse;border-spacing: 0;font-size: 1px;line-height: 1px;background-color: #e9e9e9;Margin-left: auto;Margin-right: auto" width="602">
	            <tbody><tr><td style="padding: 0;vertical-align: top">&#8203;</td></tr>
	          </tbody></table>
	        
	    </center>
	</body>
	''' % (user.name, link, delete)

    Subject = "Taskie Account Verification"

    #Send the message via local smtp server
    conn = boto.ses.connect_to_region('us-west-2',
                                      aws_access_key_id=SES_KEY,
                                      aws_secret_access_key=SES_SECRET)
    conn.send_email(taskie_mail_verification,
                    Subject,
                    "",
                    userObj.user.email,
                    html_body=html)
예제 #28
0
__author__ = ["ashwineaso"]
from models import *
from mongoengine import DoesNotExist
from settings.exceptions import *
import time
import os.path
from settings.constants import CLIENT_KEY_LENGTH, CLIENT_SECRET_LENGTH,\
    CODE_KEY_LENGTH, ACCESS_TOKEN_LENGTH, REFRESH_TOKEN_LENGTH, ACCESS_TOKEN_EXPIRATION, ACCOUNT_NOT_VERIFIED, ACCOUNT_INVITED_UNREGISTERED, ACCOUNT_ACTIVE
from settings.altEngine import Collection

tokenObj = Collection()


def createUser(userObj):
    """
	Create a new User

	::type userObj : objects
	::param userObj : An instance of Collection with the following attributes
					email,
					name,
					serverPushId,
					password_hash,
					createdOn
	::return user : An instance of user class
	"""
    try:
        invite = Invite(count=0, lastUpdate=time.time())

        user = User(email=userObj.email,
                    name=userObj.name,
예제 #29
0
def addNewTask(taskObj):
    """
	Adds a new task to the task list

	:type taskObj : object
	:para. taskObj : An object with the following attributes
			owner,
			collaborators,
			priority,
			name,
			description,
			dueDateTime,
			status
			group

	:return an object of the task class.

	"""

    #Assigning initial status to each task
    taskObj.status = Status(status=0, dateTime=time.time())

    #Define an emptly list to include all the user objects
    my_objects = []
    userObj = Collection()

    #for finding the user id of the owner
    userObj.id = taskObj.owner
    taskObj.owner = userbll.getUserById(userObj)

    #Find if the group exists. If Yes, get TaskGroup object
    groupObj.id = taskObj.group_id
    taskgroup = getGroupById(groupObj)

    #Checking whether the collaborators is a user of the app
    #If yes check whether he is a member of the group
    for userObj.email in taskObj.collaborators:
        user = userbll.getUserByEmail(userObj)
        if not [x for x in taskgroup.members if x.id == user.id]:
            raise UserNotMember

    #Creating the list of collaborators
    for userObj.email in taskObj.collaborators:
        my_objects.append(
            Collaborator(user=userbll.getUserByEmail(userObj),
                         status=taskObj.status))

    #Create a task with the necessary data.
    task = GroupTask(owner=taskObj.owner,
                     collaborators=my_objects,
                     priority=taskObj.priority,
                     name=taskObj.name,
                     description=taskObj.description,
                     dueDateTime=taskObj.dueDateTime,
                     status=taskObj.status,
                     collaborator_count=taskObj.collaborator_count).save()

    #Add the GroupTask object to the TaskGroup's task_list list
    try:
        TaskGroup.objects(id=taskgroup.id).update(push__task_list=task.id)
    except:
        raise GroupWithIDNotFound
    taskgroup.save()
    return task
예제 #30
0
def pushSyncNotification(syncObj, taskObj=Collection()):
    """
    Initiates a server side push to all the collaborators
    of the task
    """

    #Create a GCMPost object for Android Push
    androidPush = GCMPost()
    #List to store GCM ids
    androidPayload = []
    userObj = Collection()

    #Create a pseudo switch case
    #Define a function to execute for each case
    def caseTask():
        """ Task is to be synced and message to be sent to owner and collaborators """
        task = taskdal.getTaskById(syncObj)
        for coll in task.collaborators:
            if not coll.user.serverPushId in androidPayload and (
                    -1 < coll.status.status < 2):
                androidPayload.append(str(coll.user.serverPushId))
        androidPayload.append(str(task.owner.serverPushId))

    def caseGroup():
        """ Group is to be synced and message to be sent to all group members"""
        group = groupdal.getGroupById(syncObj)
        for member in group.members:
            if not member.serverPushId in androidPayload and (
                    -1 < member.status.status < 2):
                androidPayload.append(str(member.serverPushId))
        androidPayload.append(str(group.owner.serverPushId))

    def caseBuzz():
        """Buzz all the collaborators of a task """
        task = taskdal.getTaskById(syncObj)
        for coll in task.collaborators:
            if not coll.user.serverPushId in androidPayload and (
                    -1 < coll.status.status < 2):
                androidPayload.append(str(coll.user.serverPushId))

    def caseDelete():
        """Notfiy all the task users that the owner has deleted the task """
        for coll in taskObj.collaborators:
            if not coll.user.serverPushId in androidPayload and (
                    -1 < coll.status.status < 2):
                androidPayload.append(str(coll.user.serverPushId))

    def caseCollRem():
        """Norify the collaborators that they have been removed"""
        task = taskdal.getTaskById(syncObj)
        for userObj.email in taskObj.collaborators:
            coll = userdal.getUserByEmail(userObj)
            if not coll.serverPushId in androidPayload:
                androidPayload.append(str(coll.serverPushId))

    #Define the lookup dictionary
    choice = {
        "Task": caseTask,
        "Group": caseGroup,
        "Buzz": caseBuzz,
        "Deleted": caseDelete,
        "CollRemoved": caseCollRem
    }

    choice[syncObj.datatype]()  #to call appropriate case

    if len(androidPayload) > 0:
        androidPush.payload[TOKEN_GCM_REGISTRATION_IDS] = androidPayload
        androidPush.payload["data"] = syncObj.to_dict()

        # Create UrlPoster Thread for GCM Push Start Thread
        # gcmPostThread = UrlPostThread(
        #                             threadID = 1,
        #                             name = 'gcmPostThread',
        #                             postObj = androidPush
        #                             )
        # gcmPostThread.start()

        postProcess = Process(target=UrlPost, args=(androidPush, ))
        postProcess.start()
        postProcess.join()