The most efficient way to access a user objects sub-object? - logic

In my app I am using the parse framework. The basic breakdown for my current situation is that I have users who can like photo albums or photos individually. If a user likes an individual photo I want to place that photo into a new album specific to that user. That way I can easily retrieve an album filled with any given users liked photos.
I want the logic to be as simple and straight forward as possible and I have come to a conclusion, but I need another opinion to see if that's the best way to do it.
I plan to have a pointer to a 'liked photos' album as an object that is accessible on any user object. That way if a user likes a photo I can set the photoAlbumOwner as that album object on a users profile. Then for future retrieval I just need to find all photos that are associated with that album.
Every other option I have thought about requires me to fetch/search data to find the album for a specific user every time they like a photo. That would not be desirable because it's just extra data needing to be downloaded, which leads to more time.
Is this the best way to go about this or is there another option that would be more simple?

I would create an array field called likedPhotos in the _User class and then just add an reference to this liked photo.
Javascript code:
function likePhoto(photo) {
var user = Parse.User.current();
user.add('likedPhotos', photo);
user.save();
}

Related

Discord.py | How do I get a User Tag from an ID?

I am programming an entertainment bot with discord.py, and I want to code a function that allows you to look at other users' in game money and stuff with replit databases. Since making data with a user tag is inefficient since people change their usernames and tags all the time, I am using IDs. I am trying to find a way to get a user tag (eg. Dude#1234) from a user number id (eg. 871954599731396648). I couldn't find a solution. I already know how to use ctx.message.author.id but I can't find a way to make that work with every discord user.
To get the tag you can use the following method
user = await bot.fetch_user(ID) # ID must be an int and this could be could be client for you, be careful as this pings the API and can be abused if not correctly limited.
# user.discriminator will return their tag.
You can check all attributes that user can have here
To get the tag, you first have to get the user object from the id using discord.utils.get:
user_id = #insert the id of the user which you want the tag of
user = await discord.utils.get(client.get_all_members(), id =user_id)#might by something like bot.get_all_members for you
tag = user.name

Parse.com: how to best keep track of already seen images

I have an app where user can vote on a photo, then move on to the next. I need to know the most efficient strategy to keep track of the photos a user has already voted on, so he will not be presented the same photo twice.
My current strategy is to keep in each user profile an array with all already voted photos ids. I then fetch new photos and make sure their ids don't match any id in the array.
I don't think this is the proper strategy as arrays are supposed to contain a limited number of items.... and in this case a user could have viewed A LOT of images.
I don't think neither that it would be appropriate to create a class with an entry for each vote.
There are several options available in Parse.com documentation about "relations" but i'm really not sure the one to choose to:
1) Keep track photos seen by user
2) Fetch new photos excluding those
If you know the best way to do this, please advise. I'm on iOS swift / but this problem is language agnostic.
I finally established relations between photos and users as suggested:
var query = PFQuery(className:"Photos")
query.getObjectInBackgroundWithId(objectId) {
(photoEntry: PFObject!, error: NSError!) -> Void in
if error != nil {
NSLog("%#", error)
} else {
var relation = photoEntry.relationForKey("UsersThatVoted")
relation.addObject(PFUser.currentUser())
photoEntry.saveInBackgroundWithBlock {
//Rest of the query
where "UsersThatVoted" is the relation field in 'Photos' class, that links to Parse default Users class. This is triggered each time user has voted on a photo.
Then, it is very easy to make a regular query to exclude those photos with relation to current user, so he don't see twice a same photo:
query.whereKey("UsersThatVoted", notEqualTo: PFObject(withoutDataWithClassName:"_User", objectId:me.objectId))
Where me is current user. You just add this line to a regular query (to 'Photos' in my case), you don't even need to do a second inner query.

Is there a way to get previous value of an attribute in beforeSave or afterSave?

For example, I have a class "Photo" which has an attribute "of_album". If I move this photo to another album, I want the new album's photo_count increase by 1 and old album's photo_count decrease by 1. How do I do this in beforeSave or afterSave?
Currently what I'm doing is that in beforeSave, I fetch the photo object by its id and get the old album information. Is there a more convenient way to do this?
Unfortunately what you are doing is the only way to achieve this. I tried many experiments with the different change/dirty attributes and nothing could get me the "before" version of the record.
How about using Cloud function, providing the old and new album ids, then use photo.increment() with +1 / -1 to update the count.

Creating a unique ID in a form

I have a form that I have users fill out and then it gets e-mailed to me.
I am trying to get an example of how I would create an ID (based on my own conventions) that I can use to keep track of responses (and send back to the user so they can reference it later).
This is the convention I am striving for:
[YEAR]-[SERVICE CODE]-[DATE(MMDD)]-[TIME]
For example: "2012-ABC-0204-1344". I figured to add the TIME convention in the instance that two different users pick the same service on the same date rather than try to figure out how to only apply it IF two users picked the same service on the same date.
So, the scenario is that after the user goes through my wizards inputting their information and then click "Submit" that this unique ID would be created and attached to the model. Maybe something like #Model.UniqueID so that in an e-mail response I send to the user it shows up and says "Reference this ID for any future communication".
Thanks for any advice/help/examples.
In your post action
[HttpPost]
public ActionResult Create(YourModel model)
{
model.UniqueId = GenerateUniqueId(serviceCode);
}
public string GenerateUniqueId(string serviceCode)
{
return string.Format("{0}-{1}-{2}", DateTime.Now.Year, serviceCode, Guid.NewGuid().ToString().Replace("-",""); //remove dashes so its fits into your convention
}
but this seems as I'm missing part of your question. If you really want unique, use a Guid. This is what we've used in the past to give to customers - a guid or a portion of one. IF you use a portion of one ensure you have logic to handle a duplicate key. You don't need to worry about this though if using a full guid. If the idea is just to give to a customer then ignore the rest of the data and just use a guid, since it can easily be looked up in the database.

CakePHP, organize site structure around groups

So, I'm not quite sure how I should structure this in CakePHP to work correctly in the proper MVC form.
Let's, for argument sake, say I have the following data structure which are related in various ways:
Team
Task
Equipment
This is generally how sites are and is quite easy to structure and make in Cake. For example, I would have the a model, controller and view for each item set.
My problem (and I'm sure countless others have had it and already solved it) is that I have a level above the item sets. So, for example:
Department
Team
Task
Equipment
Department
Team
Task
Equipment
Department
Team
Task
Equipment
In my site, I need the ability for someone to view the site at an individual group level as well as move to view it all together (ie, ignore the groups).
So, I have models, views and controls for Depart, Team, Task and Equipment.
How do I structure my site so that from the Department view, someone can select a Department then move around the site to the different views for Team/Task/Equipment showing only those that belong to that particular Department.
In this same format, is there a way to also move around ignoring the department associations?
Hopefully the following example URLs clarifies anything that was unclear:
// View items while disregarding which group-set record they belong to
http://www.example.com/Team/action/id
http://www.example.com/Task/action/id
http://www.example.com/Equipment/action/id
http://www.example.com/Departments
// View items as if only those associated with the selected group-set record exist
http://www.example.com/Department/HR/Team/action/id
http://www.example.com/Department/HR/Task/action/id
http://www.example.com/Department/HR/Equipment/action/id
Can I get the controllers to function in this manner? Is there someone to read so I can figure this out?
Thanks to those that read all this :)
I think I know what you're trying to do. Correct me if I'm wrong:
I built a project manager for myself in which I wanted the URLs to be more logical, so instead of using something like
http://domain.com/project/milestones/add/MyProjectName I could use
http://domain.com/project/MyProjectName/milestones/add
I added a custom route to the end (!important) of my routes so that it catches anything that's not already a route and treats it as a "variable route".
Router::connect('/project/:project/:controller/:action/*', array(), array('project' => '[a-zA-Z0-9\-]+'));
Whatever route you put means that you can't already (or ever) have a controller by that name, for that reason I consider it a good practice to use a singular word instead of a plural. (I have a Projects Controller, so I use "project" to avoid conflicting with it.)
Now, to access the :project parameter anywhere in my app, I use this function in my AppController:
function __currentProject(){
// Finding the current Project's Info
if(isset($this->params['project'])){
App::import('Model', 'Project');
$projectNames = new Project;
$projectNames->contain();
$projectInfo = $projectNames->find('first', array('conditions' => array('Project.slug' => $this->params['project'])));
$project_id = $projectInfo['Project']['id'];
$this->set('project_name_for_layout', $projectInfo['Project']['name']);
return $project_id;
}
}
And I utilize it in my other controllers:
function overview(){
$this->layout = 'project';
// Getting currentProject id from App Controller
$project_id = parent::__currentProject();
// Finding out what time it is and performing queries based on time.
$nowStamp = time();
$nowDate = date('Y-m-d H:i:s' , $nowStamp);
$twoWeeksFromNow = $nowDate + 1209600;
$lateMilestones = $this->Project->Milestone->find('all', array('conditions'=>array('Milestone.project_id' => $project_id, 'Milestone.complete'=> 0, 'Milestone.duedate <'=> $nowDate)));
$this->set(compact('lateMilestones'));
$currentProject = $this->Project->find('all', array('conditions'=>array('Project.slug' => $this->params['project'])));
$this->set(compact('currentProject'));
}
For your project you can try using a route like this at the end of your routes.php file:
Router::connect('/:groupname/:controller/:action/*', array(), array('groupname' => '[a-zA-Z0-9\-]+'));
// Notice I removed "/project" from the beginning. If you put the :groupname first, as I've done in the last example, then you only have one option for these custom url routes.
Then modify the other code to your needs.
If this is a public site, you may want to consider using named variables. This will allow you to define the group on the URL still, but without additional functionality requirements.
http://example.com/team/group:hr
http://example.com/team/action/group:hr/other:var
It may require custom routes too... but it should do the job.
http://book.cakephp.org/view/541/Named-parameters
http://book.cakephp.org/view/542/Defining-Routes
SESSIONS
Since web is stateless, you will need to use sessions (or cookies). The question you will need to ask yourself is how to reflect the selection (or not) of a specific department. It could be as simple as putting a drop down selection in the upper right that reflects ALL, HR, Sales, etc. When the drop down changes, it will set (or clear) the Group session variable.
As for the functionality in the controllers, you just check for the Session. If it is there, you limit the data by the select group. So you would use the same URLs, but the controller or model would manage how the data gets displayed.
// for all functionality use:
http://www.example.com/Team/action/id
http://www.example.com/Task/action/id
http://www.example.com/Equipment/action/id
You don't change the URL to accommodate for the functionality. That would be like using a different URL for every USER wanting to see their ADDRESS, PHONE NUMBER, or BILLING INFO. Where USER would be the group and ADDRESS, PHONE NUMBER< and BILLING INFO would be the item sets.
WITHOUT SESSIONS
The other option would be to put the Group filter on each page. So for example on Team/index view you would have a group drop down to filter the data. It would accomplish the same thing without having to set and clear session variables.
The conclusion is and the key thing to remember is that the functionality does not change nor does the URLs. The only thing that changes is that you will be working with filtered data sets.
Does that make sense?

Resources