Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
We don’t allow questions seeking recommendations for books, tools, software libraries, and more. You can edit the question so it can be answered with facts and citations.
Closed 4 months ago.
Improve this question
I need to implement a message board with rating system. Something similar to stack overflow, but much simpler.
I need to rate both questions / answers and compute the rating for each user.
I'm looking modules in Drupal to implement it. Could you give me some tip ?
thanks
Fivestar, and User Points could be used for the purpose, but you only get something similar to Stack Overflow.
The first module (which requires Voting API) can be used to allow the users to vote, and the second module can be used to transform the votes in points for the users who voted (among other things — the module is not limited to this). To integrate the two modules, there is another module, but I am not sure it's part of "User Points", or User Points Contributed modules.
The problem with Fivestar is that users are allowed to give a vote from 1 to X (I think the maximum vote can be changed), which is different from the voting system used by Stack Overflow, where users can simply report "I like it", or "I don't like it". With Fivestar there would be only positive votes, and nobody would be able to down vote a comment, or a node; it would be possible to lower the average by giving the minimum vote.
Between the modules I listed, there isn't a module that allows to give points to the author of the node / comment; using "Voting API", and "User Points" it would possible to do that, but no module I looked allows to do it (this means that you could probably write a custom module).
If you look at the list of the modules included in the installation profile ArrayShift, you can get an idea of the modules you can use to reach the same purpose.
The list of modules includes
Node comments, which transforms comments in full nodes; with this module, in example, is possible to use a voting module that works only for nodes with comments too.
Voting API.
Vote UP/Down that allows users to up vote, or down vote.
User Points.
ArrayShift Support Modules; it is probable that this module contains code that allows node authors to get points every time a node they created is voted.
In particular, a module that is part of ArrayShift Support Modules (as_tweaks) contains the following code:
/**
* Below, a bunch of simple hook implementations that award userpoints based
* on various events that happen. In theory, Rules module and various other tools
* could be used to do these things, but most of those modules don't have easy
* to export/import configuration data.
*/
// VotingAPI hook. When a user casts a vote on a node, the author should
// get/lose points..
function as_tweaks_votingapi_insert($votes) {
foreach ($votes as $vote) {
if ($vote['content_type'] == 'node' && ($node = node_load($vote['content_id']))) {
// Award the points
userpoints_userpointsapi(array(
'uid' => $node->uid,
'points' => $vote['value'] * 10,
'operation' => 'vote up',
'entity_id' => $node->nid,
'entity_type' => 'node',
));
}
}
}
// VotingAPI hook. When a user casts a vote on a node, the author should
// get/lose points..
function as_tweaks_votingapi_delete($votes) {
foreach ($votes as $vote) {
if ($vote['content_type'] == 'node' && ($node = node_load($vote['content_id']))) {
// Award the points
userpoints_userpointsapi(array(
'uid' => $node->uid,
'points' => $vote['value'] * -10,
'operation' => 'vote up',
'entity_id' => $node->nid,
'entity_type' => 'node',
));
}
}
}
The Drupal Fivestar works great.
Related
I have a scenario where the first question is "How many people are in 2018" and returns 2. I then want to continue the conversation by asking "How many male and female are there".
It should return 1 male and 1 female without asking the year inferring form previous question.
How can Dialogflow and my fulfillment code infer the year?
I have tried to get the total counts, and can also get the male and female counts, but I'm not sure how to continue the conversation in a natural way.
function countresponders2018(agent){
const year = agent.parameters.year;
return admin.database().ref('data').once('value')
.then((snapshot) => {
let totalCount=0;
snapshot.forEach( childSnapshot => {
var value = childSnapshot.val();
if (value.SurveyYear==year){
totalCount+=1;
}
});
agent.add(`The total responders are ${totalCount}`);
});
This is a great question, and important to think about when designing good conversations.
I'm going to ignore the database queries, since it sounds like you may have this part under control, and it isn't directly related to the conversational parts.
Restating the problem
To rephrase what you want to do, you'd like to handle all the following phrases the same way:
How many people are in 2018?
In 2019, how many people are there?
How many people are there?
Similarly, these should all be the same:
How many male and female are there in 2018?
In 2017, how many male and female are there?
How many male and female are there?
Can you break that down by men and women?
ie - users should be able to ask questions, both specifying the year, and possibly without.
During the conversation, if they specify the year, this value should be the one assumed for further questions unless they specify a different year. This is pretty natural - humans build up short-term context in our conversations.
These also have an issue you didn't raise in your question - how to handle a question if they haven't yet specified a year. Good conversation design would suggest that you should ask for the year, and then execute the question that was originally asked. So the conversation might be something like this:
User: How many people are there?
Agent: What year would you like that for?
User: 2018
Agent: There were 2 people in 2018
Overall approach: Contexts
Fortunately - Dialogflow supports this concept directly with Contexts. This lets you save parameters in between statements from the user, so this can be a good way to store the year for later questions.
You an also make Intents that can only be triggered when specific Contexts are active. This can be useful to make sure which Intents make sense at parts of the conversation.
There are two good approaches to using Contexts for these kinds of questions. Although each has trade-offs, which one you use is largely a matter of personal style. You can also use contexts to support the scenario where you need to ask for the year if we don't already have it.
Approach 1: Single Intent per question
With this scheme, you would have a single Intent that responds to each question from the user. Your fulfillment would see if the year parameter is set and, if so, use that parameter as the year and set it in a Context's parameters. If it isn't set - then use the value from the parameters in the Context.
So our "askPeople" Intent might have the phrases we talked about above:
How many people are in [year]?
In [year], how many people are there?
How many people are there?
And we define "year" as a parameter of the #sys.number-integer for example. (Other entity types are possible, but this will do for now.)
If you're using the dialogflow-fulfillment library, our handler function for this might look something like this:
function askPeople( agent ){
// Try to get the year from the context first
let context = agent.context.get('RememberYear');
let year = context && context.parameters && context.parameters.year;
// If we don't have a year, get it from the phrase parameters
year = year || agent.parameters.year;
if( year ){
// If we do have a value, get the result, reply,
// and save the year in the context.
return getPeople( year )
.then( count => replyPeople( agent, year, count ) );
} else {
// We don't have a value
// FIXME: We'll discuss what to do about this below
}
}
You'll need to write the getPeople() function to return a Promise that resolves to the results from your database. I also pulled out the replyPeople() function intentionally. It might look something like this
function replyPeople( agent, year, count ){
agent.context.set({
name: 'RememberYear',
lifespan: 99,
parameters:{
year: year
}
});
agent.add( `The total count for ${year} was ${count}.` );
}
Approach 2: Multiple Intents per question
With this, we will have two different Intents that handle the question. One accepts it with the year, while the other handles the phrase without the year. The big difference is that the one without the year in the training phrase will require the "RememberYear" Context to be set in order to trigger.
The base Intent ("askPeopleYear") is the fairly familiar one with training phrases such as
How many people are in [year]?
In [year], how many people are there?
And the "year" parameter defined the same way as above.
Our other Intent ("askPeopleNoYear") would have the Input Context of "RememberYear" set and have a training phrase such as
How many people are there?
And would not have any parameters.
We'll likely need a third Intent, or at least additional way to deal with, what happens if the "RememberYear" Context isn't set, but they say that phrase. We'll discuss this below.
The fulfillment code would require two different handler functions that might look something like this
function askPeopleYear( agent ){
// We know the year is in the parameter
let year = agent.parameters.year;
// Get the result, reply, and set the context
return getPeople( year )
.then( count => replyPeople( agent, year, count ) );
}
function askPeopleNoYear( agent ){
// We know the year is in the context
let context = agent.context.get('RememberYear');
let year = context && context.parameters && context.parameters.year;
// Get the result, reply, and set the context
return getPeople( year )
.then( count => replyPeople( agent, year, count ) );
}
The getPeople() and replyPeople() functions would be the same as in our previous approach.
Dealing with no year set
So what happens if they say "How many people are there", but we don't have the "RememberYear" Context set with a value?
In the first approach, this gets to the else condition which we marked with a "FIXME". In the second approach, a Fallback Intent would be triggered if we don't put something else in place, and this doesn't really help the user.
In either case, what we should do is ask the user for the year they want and create an Intent to capture the year. Since we may need to do this for different question types, we should also store which function to execute in a... you guessed it... Context. So let's assume that we set a "NeedsYear" Context with a parameter named "functionName" to track which function we'll need to call.
This Intent (let's name it "provideYear") would require the "NeedsYear" Input Context and might have training phrases such as:
[year]
Get it for [year]
And take a "year" parameter, same as we've defined above. (We might even mark this as required.)
The handler for this might look something like
function provideYear( agent ){
// We know we have the parmeter
let year = agent.parameters.year;
// We also know we have the context with the function name
let context = agent.context.get('NeedsYear');
let functionName = context && context.parameters && context.parameters.functionName;
// We should clear this context, since we no longer need the year
agent.context.set({
name: 'NeedsYear',
lifespan: 0
};
// And then call whichever function is appropriate
if( functionName === 'people' ){
return getPeople( year )
.then( count => replyPeople( agent, year, count ) );
} else if( functionName === 'gender' ){
// ...
}
}
Summary
Use Contexts.
Contexts serve as good gatekeepers for which Intents can be triggered, and also a good way to store values between turns of a conversation.
Contexts are powerful.
I want to make a simple social network website using drupal 7. There will be a relationship type like 'friendship'. After a lot of Googling, I haven't found any way to forbid non-friend people from viewing a specific field. For example, there could be a field containing the user's phone number - I would want other users not to be able to see this field unless they are the user's friend. How do you do this? Are there any modules or anything else that could help me?
Your best friend would be your custom module that has hook_field_access() properly set up in it.
EXAMPLE:
function MYMODULE_field_access ($op, $field, $entity_type, $entity, $account) {
switch ($entity->type) {
case 'REFERENCED_NODE_TYPE_NAME': {
///DO YOUR STUFF HERE: SET A $VAR TO 'TRUE' OR 'FALSE' DEPENDING IF YOU WANT TO GIVE ACCESS.
}
}
return $var;
}
I need a little help to better understand how to do something or the best approach in Meteor.JS
In my app I currently have a user which has topics and topics have a list of posts, each topic has a comments and a posts / comments count.
I would like to add collaborators to each topic IE a user can invite someone to add posts and comments to a specific topic basically sharing or collaborating under that topic which is then private to the two or X amount of users.
What's the best approach for this when it comes to Meteor Pub/Sub and Mongo collections.
Thanks,
Almog
There are many ways to solve this. For example, instead of tying topic to a single user, add a param that would hold _ids of all users allowed to the topic:
sampleTopic = {
_id: 'fpoierj9',
title: 'Sample',
userIds: [
'opijo42',
'ik03agg',
'po32a0v',
],
};
Now, in your publish channel, show topics that contain your user Id in said array:
Meteor.publish('topics', function() {
return Topics.find({userIds: this.userId});
});
We've been having a new type of spam-bot this week at PortableApps.com which posts at a rate of about 10 comments a minute and doesn't seem to stop - at least the first hour or so (we've always stopped it within that time so far). We've had them about a dozen times in the last week - sometimes stopping it at 50 or 60, sometimes up to 250 or 300. We're working to stop it and other spam bots as much as possible, but at the moment it's still a real pest.
I was wondering whether in the mean time whether there's any sort of module to control the frequency a user can post at to e.g. 50 an hour or something like 10 in an hour for new users. That at least would mean that instead of having to clear up 300 comments 50 at a time in admin/content/comment we'd have a smaller number to clear. (A module to add a page to delete all content by a user and block them would also be helpful!)
I believe that there's a plugin to do this available for WordPress, but can't find any such thing for Drupal.
For your second question, i would have a look at the code of the User Delete module (click).
The module also disables the user account and unpublished all nodes/comments from a certain user. By extending the code, you could easily create another possibility to unpublish + delete all nodes/comments from a certain user and blocking the account.
After the unpublish code in the module, you should just put delete code (in sql if the module is selecting by a sql-query or by using the drupal delete functions).
Another option would be so make a view (using the view module) only to be viewed by administrators, where you choose a certain user using the filters and then lists his/her posts. Then in the node-contenttype.tpl.php you place a button that calls a function which deletes all nodes/comments and the user.
First problem (post frequency)
I've been thinking about the comment post limit. If I remember correctly Drupal stores comments in a seperate table and has comment specific functions.
I'd create a new module and using the comment_nodeapi function i would check in the operation 'insert' how much comments the current user has already made within a certain timeframe.
To check this I would write a custom sql query on the database which takes the count of alle comments made by uid where the post_date is larger then NOW-1hour. If that count is larger then 10 or 15 or whatever post frequency you want then you give a message back to the user. You can retrieve the user id and name by using the global $user variable.
(example: print $user->name;)
You have to check on your own for the sql query but here's some code when you have the amount:
<?php
function comment_nodeapi(&$node, $op, $arg = 0) {
switch ($op) {
case 'insert':
//PLACE HERE THE SQL TO GET THE COUNT
if($count > 15){
$repeat = FALSE;
$type = 'status'
drupal_set_message("You have reached the comment limit for this time.", $type, $repeat);
break;
}else{
db_query('INSERT INTO {node_comment_statistics} (nid, last_comment_timestamp, last_comment_name, last_comment_uid, comment_count) VALUES (%d, %d, NULL, %d, 0)', $node->nid, $node->changed, $node->uid);
break;
}
}
}
?>
(this code has not been tested so no guarantees, but this should put you on the right track)
I would suggest something like Mollom (from the creator of Drupal). It scans the message for known spam pattern/keywords/... and if this scan fails, it displays a CAPTCHA to the user to make sure that it's a real human that wants to enter content that has the same properties like spam.
They offer a free service and some paid solutions. We are using it for some customers and it's worth the money. It also integrates very well in Drupal.
Comment Limit is probably what you need.
http://drupal.org/project/spam
http://drupal.org/project/antispam - with akismet support
I run drupal 6 and want to code this functionality:
after the user filled out the formular he can click an extra button, which will make the form readonly for him.
I thought about an hidden_field and an extra button, which after the user clicked the extra button set the hidden_field to a true state. When I load the node and the hidden_field has the true state, I want to set all the fields in the node to readonly. (hook_access, node_access?!?)
puh.. hope this all is not too confusing (because even I am now a little confused...)
Firstly you won't be able to stop someone who has access to the database or the root user from seeing the data (at least not without some encryption).
In terms of normal site operation this isn't too hard to do. The two hooks you need to invoke are hook_node_grants() and hook_node_access_records(), there is quite a good example, which also pretty much does what you want in the question, here.
Put simply hook_node_access_records() returns a structure detailing relms and ids which can perform actions on it, and hook_node_grants() returns the relms and ids for a user. If there is a match between the two then access (read or write) is granted.
This gives you a lot of flexibility. One example would be that people could only read nodes created by other people with the same star sign. In hook_node_grants you would examine the user object to get the starsign and return $grants['starsign'] = 2
When a node is saved hook_node_access_records would have to check the star sign of the user who created it do something like:
$grants = array();
$grants[] = array(
'realm' => 'starsign',
'gid' => $account->starsign,
'grant_view' => 1,
'grant_update' => 0,
'grant_delete' => 0,
'priority' => 0,
);
return $grants
That way if the relm and group id match the user will be given read access.