Próbuję wprowadzić system głosowania podobny do stackoverflow lub reddit, gdzie użytkownik może głosować tylko raz na dany wpis.Rozgłaszanie i notowanie z kręgosłupem, ekspresowym i mangowym
Po wykonaniu zaleceń podanych tutaj
storing upvotes/downvotes in mongodb
Stworzyłem dwa schematy do przechowywania upvotes i downvotes. Dla każdego użytkownika śledzę posty, na które głosował użytkownik.
post schematu: Schemat
var postSchema = new Schema({
name: String,
votes: Number,
votetype: Number,
postedBy: { type: String, ref: 'User' },
});
użytkownika:
var userSchema = new Schema({
twittername: String,
twitterID: Number,
votedPosts : [{ _id : mongoose.Schema.Types.ObjectId , votetype: Number }]
});
zależności od aktualnego użytkownika każdy post będzie mieć inny pogląd, jeśli użytkownik głosował na stanowisku przed przycisk upvote lub przycisk downvote będzie pomarańczowy (podobny do stackoverflow), więc mam następujący (uproszczony) model szkieletu dla postu:
var PostModel = Backbone.Model.extend({
urlRoot : '/tweet',
idAttribute: '_id',
defaults:{
name: '',
votes: 0,
votetype: 0,
postedBy : '',
},
upvote: function(){
this.set ({votetype : 1 }, {votes : this.get('votes') + 1});
this.save();
$.ajax({
type: "POST",
url:"/upvote",
data : {postID : this.id , userID : window.userID , vote: 1},
success : function(result){
console.log(result);
},
error: function(jqXHR, textStatus, errorThrown) {
console.log(textStatus, errorThrown);
}
});
},
});
Tak więc typ głosowy zaczyna się od "0", jeśli użytkownik nie głosował wcześniej na ten wpis, a jego "1" lub "-1" w zależności od głosowania. W funkcji upvote, jak aktualizować i zapisać votetype tego posta, ja również wysłać ajax żądania dodać, że stanowisko do głosowania posty tablicy użytkownika w sterowniku postu tak:
exports.upvote = function(req,res){
var postID = req.body.postID;
var newvotetype = req.body.vote;
User.findOne({twitterID : req.body.userID}, {votedPosts : { $elemMatch: { "_id": postID }}},
function(err, post) {
if (post.votedPosts.length == 0) {
//append to the array
User.update({twitterID : req.body.userID} , { $push : {votedPosts : {_id : postID , votetype: newvotetype}}} ,function (err, user, raw) {
if (err){console.log(err);}
});
console.log(post);
console.log("no one has voted on this before");
}
else {
//update in the existing array
User.update({twitterID : req.body.userID, 'votedPosts._id': postID }, { $set : {'votedPosts.$.votetype' : newvotetype}} ,function (err, user, raw) {
if (err){console.log(err);}
});
}
}
);
res.send("success");
res.end();
};
mogę mieć niektóre złe decyzje projektowe, ale jak na razie wygląda na to, że to działa dobrze. Proszę, proszę powiedz mi, czy mogę ulepszyć mój kod lub cokolwiek innego na moim projekcie.
Teraz jest trudna część. Jakoś muszę patrzeć przez oba te schematy i zmienić „votetype” każdego postu przed wykonaniem collection.fetch() .. I wymyślił rozwiązanie brzydki jak ten:
https://gist.github.com/gorkemyurt/6042558
(í umieścić go w gitarze, więc być może jest on bardziej czytelny, przepraszam za brzydki kod ...)
i raz zaktualizuję typ głosu każdego posta w zależności od użytkownika, przekazuję go do mojego widoku kręgosłupa, aw moim szablonie Zrób coś bardzo prostego jak:
<div class="post-container">
<div id="arrow-container">
<% if (votetype == 1) { %>
<p><img id="arrowup" src="/images/arrow-up-orange.jpg"></p>
<p><img id="arrowdown" src="/images/arrow-down.jpg"></p>
<% } %>
<% if (votetype == 0) { %>
<p><img id="arrowup" src="/images/arrow-up.jpg"></p>
<p><img id="arrowdown" src="/images/arrow-down.jpg"></p>
<% } %>
<% if (votetype == -1) { %>
<p><img id="arrowup" src="/images/arrow-up.jpg"></p>
<p><img id="arrowdown" src="/images/arrow-down-orange.jpg"></p>
<% } %>
</div>
<div id="text-container">
<p><h2><%- name %></h2></p>
<p><%- dateCreated %></p>
<p>Posted by: <%- postedBy %></p>
</div>
</div>
To rozwiązanie działa, ale nie sądzę, żeby naprawdę skutecznie sprawdzał wszystkie posty i wszystkie posty, na które użytkownik głosował za każdym razem, gdy użytkownik otwiera stronę, aby wyświetlić niestandardowy widok wpisów. Czy każdy może pomyśleć o lepszy sposób na zrobienie tego? Jestem otwarty na wszelkie rady i krytyki na temat mojego kodu .. z góry dzięki
wielkie dzięki za odpowiedź, to było naprawdę pomocne. Próbuję się tylko nauczyć ... czy możesz wyjaśnić tę część jeszcze raz "Ale, jak zareaguje twoja aplikacja, jeśli atakujący wyśle 100, a nawet 1000 głosów? Ta operacja powinna być atomowa i powinieneś zwiększać głosy na serwerze, kiedy robisz Żądanie POST do punktu końcowego/upvote. " –
Tak, z tego, co napisałeś, doszedłem do wniosku, że robisz dwie prośby: jedną, gdy zapisujesz 'PostModel': this.save(); i jeden zaraz po tym, gdy tworzysz 'POST/upvote'. Zgłaszasz prośbę o przypisanie głosu użytkownika i, podobnie jak w innych miejscach, musisz upewnić się, że użytkownicy nie mogą go wykorzystać. Co się stanie, jeśli jakiś użytkownik wyśle tylko pierwszą prośbę - tę, która zwiększa głosowanie, ale nie wysyłając drugiej - w zasadzie robi to anonimowo. Właściwym sposobem byłoby po prostu przypisywanie nowych wartości w modelu bez wywoływania 'this.save' i zapisywanie do databe z * twojego * kodu po stronie serwera'/upvote' –
Jak dodać lub zmienić głosowanie? Z mojego obecnego rozumienia MongoDB musiałbym najpierw sprawdzić, czy jest głosowanie na użytkownika, a następnie dodać lub zmienić głos. Ale co się stanie, jeśli zostanie mu przyznany kolejny głos po sprawdzeniu, czy jest głosowanie? –