Is there any way using Python / JS to forward messages which I, as a member, do receive in a private read-only group? I'm trying to set it up using python-telegram-bot but it seems I gotta add the bot to the group to have it interact with the contents sent in the group. But I can't as Im just a reading / receiving member...
Is there maybe a way without using the Telegram API, but using some sort of JS Browser automation to forward those? This is the only thing which comes to my mind... Thanks in advance!
Answering my own question in case someone needs it.
As #CallMeStag pointed out, one needs a library which support "User bots". These are librarys directly implementing the MTProto.
For python, e.g. Pyrogram is suitable and very easy to use.
First of all, one needs an API key and API hash to identify the Python Script on the Telegram server to communicate in the MTProto.
https://my.telegram.org/auth?to=apps -> Login using your credentials and create an "App". Define those into API_ID and API_HASH below.
Now, I use this code to copy messages from the SOURCE_CHAT to the TARGET_chat:
#!/usr/bin/env python3
from pyrogram import Client
from pyrogram import filters
# ~~~~~~ CONFIG ~~~~~~~~ #
ACCOUNT = "#xy"
PHONE_NR = '+49....'
# https://my.telegram.org/auth?to=apps
API_ID = 1111111
API_HASH = "your_hash"
# CHAT ID
SOURCE_CHAT = -11111
TARGET_CHAT = -22222
# ~~~~~~~~~~~~~~~~~~~~~~ #
app = Client(
ACCOUNT,
phone_number=PHONE_NR,
api_id=API_ID,
api_hash=API_HASH
)
# filters.chat(SOURCE_CHAT)
#app.on_message(filters.chat(SOURCE_CHAT))
def my_handler(client, message):
message.copy( # copy() so there's no "forwarded from" header
chat_id=TARGET_CHAT, # the channel you want to post to
caption="Copied from XYZ" # Caption
)
app.run()
To find out the CHAT_ID of Source and Target, I temporarly disabled the Filter, and printed the message.
#app.on_message()
def my_handler(client, message):
print(message)
Doing so, enables you to: whenever receiving a message in the specific group, you can find message.chat.id (attention: negative Values!). Configure those for SOURCE_CHAT and TARGET_CHAT in the full script above.
EDIT:
Another option to get all chat IDs for all dialogues without first needing someone to send a message in the channel/group/private/chat:
def getAllChatIDs():
for x in app.get_dialogs():
print (x.chat.type, x.chat.title, x.chat.id)
Simply call it once and you'll get a list of dialogues :)
It's indeed not possible with Telegram Bots - you'd have to add them to the group. You can however automate your personal account using so called "user bots". Here is an article about them.
Related
I'm working with the Plaid API found here but can't seem to get the quickstart to run properly. My latest attempt is below
import base64
import os
...
...
app = Flask(__name__)
# Fill in your Plaid API keys - https://dashboard.plaid.com/account/keys
PLAID_CLIENT_ID = 'xxxxxxxx' #os.getenv('xxxxx')
PLAID_SECRET = 'xxxxx' #os.getenv('xxxx')
...
PLAID_ENV = 'sandbox' #os.getenv('PLAID_ENV', 'sandbox')
...
PLAID_PRODUCTS = 'transactions' #os.getenv('PLAID_PRODUCTS', 'transactions').split(',')
...
PLAID_COUNTRY_CODES = 'US' #os.getenv('PLAID_COUNTRY_CODES', 'US').split(',')
def empty_to_none(field):
value = os.getenv(field)
if value is None or len(value) == 0:
return None
return field
...
PLAID_REDIRECT_URI = empty_to_none('http://localhost:8000/oauth-response.html')
client = plaid.Client(client_id=PLAID_CLIENT_ID,
secret=PLAID_SECRET,
environment=PLAID_ENV,
api_version='2019-05-29')
#app.route('/')
def index():
return render_template('index.html',)
When I run server.py and open the browser the button can't be selected. Also the list of banks just continuously loads. So I check chrome dev tools I find the error link-initialize.js:1 Uncaught Error: Missing Link parameter. Link requires a key or token to be provided. Is this because I didn't pass something in render_template? I can't tell from the index.html file found here & currently that's the only front end document referenced in the (python) repository. I looked at the question found here but it's several years old & I believe the integration has changed...
The problem here is that you're specifying a REDIRECT_URI but haven't configured the developer dashboard to accept that as your URI.
Unfortunately, the error messaging is currently swallowed and only visible in the network tab. We're going to fix it so that these errors are propagated into a place where they're more visible.
I am attempting to set up the sharing ability on a web application that I am making. I have followed the steps on Google's Drive Sharing Instruction Page to the best of my ability. However, when I click the button, I get the expected popup, but with the message "Sorry, sharing is unavailable at this time. Please try again later."
The code I have is slightly different, as the init function name is being used elsewhere. The code I have is:
function initializeGoogleApis() {
/*
self._shareClient = {
'showSettingsDialog': function() {
devConsole.warning(0, "The sharing ability has not yet been implemented.");
}
};*/
gapi.load('drive-share', function() {
self._shareClient = new gapi.drive.share.ShareClient();
self._shareClient.setOAuthToken(self.clientId);
self._shareClient.setItemIds(self.realtimeUtils.getParam("id"));
});
}
Note the commented section. I had this to insure that the 'share' button on my page is loaded properly and calling the function, which it is. As explained in the title, when I click the button, I get a 500 error in the console.
At the bottom of the Google page listed above, it says the following:
The user is signed in to Google --> I have done this
The user has installed your app --> I don't know about this. For all other functionality, I only have to visit the site, so I am not sure what the difference here is.
The URL of the page that launches the dialog must have the same origin as the Open URL registered for the app --> I think I have this done. I followed the link on the page (here) and verified ownership.
I am also testing on the actual host, not on localhost as it states this will not work.
All the same, I get the following error:
GET https://drive.google.com/sharing/share?id=xxxxx_xxxxxxxxxx8&fore…
d=false&client=postMessage&embedOrigin=http://www.example.com 500 ()
_.k.$l # cb=gapi.loaded_0:651
_.k.S # cb=gapi.loaded_0:651
_.k.Ql # cb=gapi.loaded_0:794
ys.kc # cb=gapi.loaded_0:791
Ts.OV # cb=gapi.loaded_0:822
Zs # cb=gapi.loaded_0:814
FM # cb=gapi.loaded_0:818
Ts.Ph # cb=gapi.loaded_0:818
pt.Na # cb=gapi.loaded_0:829
onclick # ?id=xxxxx_xxxxxxxxxxxxxxxxxxx:97
Any help would be appreciated
It looks like you are passing in your clientID instead of your OAuth token.
I've been told by BC support that this isn't possible, but I would be surprised if there really wasn't a way.
I need to be able to automatically assign a customer to a specific customer group when they create an account. My thought:
I would add an extra field to the sign-up form
Provide a user with a code (a string or number)
User enters code when creating new account
User hits submit
On form submit I would grab the value of the extra field:
var codeInput = document.getElementById('code-input').value;
I would then compare that value to a pre-defined string, and if there is a match, I would assign that customer to groupX (with a group id of 8):
if ( codeInput === "codeIGaveToTheUser" ) {
currentUserGroupID = 8;
}
Is it possible to assign a customer to a specific group on sign-up like this (or any other way)?
Any help is much appreciated.
Although using BigCommerce webhooks would ensure the highest success rate of executing your customer group assignment app, it requires quite a bit of setup on BigCommerce (creating a draft app, getting an oAuth key, jumping jacks, etc), and may be a bit of overkill for your requirements.
Here's an easier way, in my {mostly} humble opinion, that takes advantage of much of what you included in your original question. Any solution though will nonetheless require an external server to handle the customer group assignment through the BigCommerce API.
Within the BigCommerce control panel, add in the extra field to the user sign up form like you mentioned.
So as you can see, this new input field has been added natively to the default registration page:
So now, when a user creates an account on your site, the value for the Signup Code (the custom field created) will be directly accessible through the API for that customer's account. Take a look at what that JSON data looks like:
Okay, so this is nice and all, but how do we automate it?
To do so, we will have to let our external application know that a customer just registered. Furthermore, our external application will need some sort of reference to this newly created customer, so that it knows which customer to update the customer group for. Normally a BigCommerce webhook would notify us of all this, but since we aren't using a BigCommerce webhook, here's the alternative method to triggering the external script.
We will trigger our external application via the BigCommerce Registration Confirmation page - createaccount_thanks.html. This page is loaded immediately after a customer creates an account, so it is the perfect place to insert our trigger script.
Additionally, now that the customer is logged in, we can access the customer's email address via a BigCommerce Global system variable -%%GLOBAL_CurrentCustomerEmail%%.
We should make an HTTP request from this page to our external application along with the customer's email address. Specifically, we can make an XMLHttpRequest via JavaScript, or to be modern, we'll use Ajax via jQuery. This script should be inserted before the closing </body> tag on createaccount_thanks.html.
Example of POST request (although a GET would suffice as well):
<script>
$(function() {
$('.TitleHeading').text('One moment, we are finalizing your account. Please wait.').next().hide(); // Let the customer know they should wait a second before leaving this page.
//** Configure and Execute the HTTP POST Request! **//
$.ajax({
url: 'the_url_to_your_script.com/script.php',
type: 'POST',
contentType: 'application/json',
data: JSON.stringify({email:"%%GLOBAL_CurrentCustomerEmail%%"}),
success: function() {
// If the customer group assignment goes well, display page and proceed normally. This callback is only called if your script returns a 200 status code.
$('.TitleHeading').text('%%LNG_CreateAccountThanks%%').next().show();
},
error: function() {
// If the customer group assignment failed, you might want to tell your customer to contact you. This callback is called if your script returns any status except 200.
$('.TitleHeading').text('There was a problem creating your account').after('Please contact us at +1-123-456-7890 so that we can look into the matter. Please feel free to continue shopping in the meantime.');
}
});
});
</script>
Now finally, you just need to create your serverside application responsible for handling the request above, and updating the customer's customer group. You can use any language that you desire, and BigCommerce even offers several SDK's you can use to save mega development time. Just remember that you need to host it somewhere online, and then insert its URL to the JS script above.
PHP Example (quick & dirty):
git clone https://github.com/bigcommerce/bigcommerce-api-php.git
curl -sS https://getcomposer.org/installer | php && php composer.phar install
<?php
/**
* StackOverflow/BigCommerce :: Set Customer Group Example
* http://stackoverflow.com/questions/37201106/
*
* Automatically assigning a customer group.
*/
//--------------MAIN------------------------//
// Load Dependencies:
require ('bigcommerce-api-php/vendor/autoload.php');
use Bigcommerce\Api\Client as bc;
// Define BigCommerce API Credentials:
define('BC_PATH', 'https://store-abc123.mybigcommerce.com');
define('BC_USER', 'user');
define('BC_PASS', 'token');
// Load & Parse the Email From the Request Body;
$email = json_decode(file_get_contents('php://input'))->email;
// Execute Script if API Connection Good & Email Set:
if ($email && setConnection()) {
$customer = bc::getCollection('/customers?email=' .$email)[0]; //Load customer by email
$cgid = determineCustomerGroup($customer->form_fields[0]->value); //Determine the relevant customer group ID, via your own set string comparisons.
bc::updateCustomer($customer->id, array('customer_group_id' => $cgid)) ? http_send_status(200) : http_send_status(500); //Update the customer group.
} else {
http_send_status(500);
exit;
}
//-------------------------------------------------//
/**
* Sets & tests the API connection.
* #return bool true if the connection successful.
*/
function setConnection() {
try {
bc::configure(array(
'store_url' => BC_PATH,
'username' => BC_USER,
'api_key' => BC_PASS
));
} catch (Exception $e) {
return false;
}
return bc::getResource('/time') ? true : false; //Test Connection
}
/**
* Hard define the customer group & signup code associations here.
* #param string The code user used at signup.
* #return int The associated customergroup ID.
*/
function determineCustomerGroup($signupCode) {
switch ($signupCode) {
case 'test123':
return 1;
case 'codeIGaveToTheUser':
return 8;
default:
return 0;
}
}
So then you would do your customer group string comparisons directly in the serverside program. I'd recommend you rewrite your own BC API script as the one above in quality is really something along the lines of functional pseudo-code, but more so present to show the general idea. HTH
You would need to set up a server to listen for webhooks unless you wanted to do a cron job. We have some basic information on the developer portal, but I included more resources below. From there, you'd need to choose your server language of choice to listen for the webhooks once they been created, respond correctly (200 response if received), execute code based on this information, and then take action against the BC API.
So if you were looking for a code, you'd need to listen for the store/customer/created webhook, and have your code look for a custom field that contained the code. If it was present, then take action. Else, do nothing.
https://developer.github.com/webhooks/configuring/
http://coconut.co/how-to-create-webhooks
How do I receive Github Webhooks in Python
I am slightly misunderstand Paypal flow event after reading https://developer.paypal.com/docs/api/. I'd like to integrate express checkout and credit card payments to my site. I am using Flask and paypalrestsdk without any Flask extensions.
Here is excerpts from my app:
#app.route('/', methods=['GET'])
def index():
# Page with but form, price/quantity/name values
# are stored in hidden fields, "Buy now" acts as submit
return render_template('index.html')
#app.route('/payment/paypal', methods=['POST'])
def payment_paypal():
# Here I am creating dict with required params
payment_template = {
'intent': 'sale',
'payer': {'payment_method': 'paypal'},
'redirect_urls': {
'return_url': url_for('payment_paypal_execute'),
'cancel_url': url_for('payment_paypal_error')
},
......
}
payment = paypalrestsdk.Payment(payment)
if payment.create():
print('Payment "{}" created successfully'.format(payment.id))
for link in payment.links:
if link.method == "REDIRECT":
redirect_url = str(link.href)
print('Redirect for approval: {}'.format(redirect_url))
return redirect(redirect_urls)
#app.route('/payment/paypal/execute', methods=['GET'])
def payment_paypal_execute():
payer_id = request.args.get('payerId')
payment_id = request.args.get('paymentId')
token = request.args.get('token')
pending_payment = PayPalPayment.query.filter_by(token=token).filter_by(state='created').first_or_404()
try:
payment = paypalrestsdk.Payment.find(pending_payment.payment_id)
except paypalrestsdk.exceptions.ResourceNotFound as ex:
print('Paypal resource not found: {}'.format(ex))
abort(404)
if payment.execute({"payer_id": payer_id}):
pending_payment.state = payment.state
pending_payment.updated_at = datetime.strptime(payment.update_time, "%Y-%m-%dT%H:%M:%SZ")
db.session.commit()
return render_template('payment/success.html', payment_id=payment.id, state=payment.state)
return render_template('payment/error.html', payment_error=payment.error, step='Finallizing payment')
It is works fine, after clicking on button payment created succesfully (with state created) user redirected to approval page. There he click "Confirm"... And I never returned to my application, event when I specifying return_url! I.e. application could never be informed that buyer approved payment and it should be updated in my own database and new license should be sent to that person.
Problems:
I cannot find way to define some callback using pyhtonrestsdk. How to do it?
Even if I adding callback (I tried embed Express Checkout using pure Javascript button code) with data-callback my application was not called. I suspect because remote server could not call http://127.0.0.1/payment/paypal/success
User could close window with PayPal confirmation immediately after click "Confirm" so I could not trust browser redirection it it performed somehow later.
Finally, I suspect that I do not understand PayPal workflow clear, but I could not find more information about it event on developers portal.
As usual, devil hides in details. My main issue was following: paypal does not redirects me to my application, but I found that it redirects me (after confirmation) to URL which looks like https://sandbox.paypal.com/ with query string contains desired parameters. I.e. redirect_urls works as expected, just redirects me to wrong host.
After that I remembered that url_for generate relative links. So just added keyword _external=True I've been redirected to my application with all required arguments and payment successfully confirmed and executed.
I.e. correct redirect_urls block will looks like:
'redirect_urls': {
'return_url': url_for('payment_paypal_execute', _external=True),
'cancel_url': url_for('payment_paypal_error', _external=True)
}
Finally I've got following workflow:
Opened / (index) which has button Pay with PayPal It is image button inside form. Beside this button form contains hidden fields with amount, product name and quantity (actually if is not good idea because we cannot trust to user, so I storing only product_license_type_id which stored in DB and contains all required information about product).
Once clicked it POST form to '/payment/paypal' (paypal_create) where create object Payment with filling all fields. If call payment.create finished successfully it also creates record in my own database with payment_id and state (these fields related to paypal workflow, of course actually I am storing couple of other fields related to my app).
Once payment created on PayPal side, application look into response for list payment.links. We want one with rel == 'approval_url' and method == 'REDIRECT' and return flask.redirect(found_link)
On PayPal site buyer should click 'Approve', review shipping address and after that he will be immediately redirected to redirect_urls.return_url with following parameters in query string: PayerID, paymentId, token.
Once redirected back you should get this parameters from query string (keep in mind - it is case-sensitive!), find payment using PayPal API (payment = paypalrestsdk.Payment.find(payment_id)) and finalize it (payment.execute({"payer_id": payer_id}):).
When finalized payment changes status to approved.
....
PROFIT!
UPD: You do not need to turn on "AutoRedirect" in you selling account preferences and this approach suitable for integrating one account into multiple sites.
I am creating a new website. I want to promote it using another my topic-related web service. I want to send some gifts to people which popularized my first website and fanpage. How to filter out lets say 20 users which likes/shares/comments most of my posts?
Any suitable programming language will be good.
[EDIT]
Ok... to be honest I looking a way to parse a fanpage that is not mine. I want to send gifts to the most active users of fanpage of my competition, to simply bribe them a little :)
There are a number of ways, I'll start with the easiest...
Say there's a brand name or #hashtag involved then you could user the search API as such: https://graph.facebook.com/search?q=watermelon&type=post&limit=1000 and then iterate over the data, say the latest 1000 (the limit param) to find out mode user (the one that comes up the most) out of all the statuses.
Say it's just a page, then you can access the /<page>/posts end point (eg: https://developers.facebook.com/tools/explorer?method=GET&path=cocacola%2Fposts) as that'll give you a list of the latest posts (they're paginated so you can iterate over the results) and this'll include a list of the people who like the posts and who comment on them; you can then find out the mode user and so on.
In terms of the code you can use anything, you can even run this locally on your machine using a simple web server (such as MAMP or WAMP, etc...) or CLI. The response is all JSON and modern languages are able to handle this. Here's a quick example I knocked up for the first method in Python:
import json
import urllib2
from collections import Counter
def search():
req = urllib2.urlopen('https://graph.facebook.com/search?q=watermelon&type=post')
res = json.loads(req.read())
users = []
for status in res['data']:
users.append(status['from']['name'])
count = Counter(users)
print count.most_common()
if __name__ == '__main__':
search()
I've stuck it up on github if you want to refer to it later: https://github.com/ahmednuaman/python-facebook-search-mode-user/blob/master/search.py
When you run the code it'll return an ordered list of the mode users within that search, eg the ones who've posted the most comments with the specific search tag. This can be easily adapted for the second method should you wish to use it.
Based on Ahmed Nuaman answer (please also give them +1), I have prepared this piece of code:
example of usage:
To analyze most active facebook users of http://www.facebook.com/cern
$ python FacebookFanAnalyzer.py cern likes
$ python FacebookFanAnalyzer.py cern comments
$ python FacebookFanAnalyzer.py cern likes comments
notes: shares and inner comments are not supported
file: FacebookFanAnalyzer.py
# -*- coding: utf-8 -*-
import json
import urllib2
import sys
from collections import Counter
reload(sys)
sys.setdefaultencoding('utf8')
###############################################################
###############################################################
#### PLEASE PASTE HERE YOUR TOKEN, YOU CAN GENERETE IT ON:
#### https://developers.facebook.com/tools/explorer
#### GENERETE AND PASTE NEW ONE, WHEN THIS WILL STOP WORKING
token = 'AjZCBe5yhAq2zFtyNS4tdPyhAq2zFtyNS4tdPw9sMkSUgBzF4tdPw9sMkSUgBzFZCDcd6asBpPndjhAq2zFtyNS4tsBphqfZBJNzx'
attrib_limit = 100
post_limit = 100
###############################################################
###############################################################
class FacebookFanAnalyzer(object):
def __init__(self, fanpage_name, post_limit, attribs, attrib_limit):
self.fanpage_name = fanpage_name
self.post_limit = post_limit
self.attribs = attribs
self.attrib_limit = attrib_limit
self.data={}
def make_request(self, attrib):
global token
url = 'https://graph.facebook.com/' + self.fanpage_name + '/posts?limit=' + str(self.post_limit) + '&fields=' + attrib + '.limit('+str(self.attrib_limit)+')&access_token=' + token
print "Requesting '" + attrib + "' data: " + url
req = urllib2.urlopen(url)
res = json.loads(req.read())
if res.get('error'):
print res['error']
exit()
return res
def grep_data(self, attrib):
res=self.make_request(attrib)
lst=[]
for status in res['data']:
if status.get(attrib):
for person in status[attrib]['data']:
if attrib == 'likes':
lst.append(person['name'])
elif attrib == 'comments':
lst.append(person['from']['name'])
return lst
def save_as_html(self, attribs):
filename = self.fanpage_name + '.html'
f = open(filename, 'w')
f.write(u'<html><head></head><body>')
f.write(u'<table border="0"><tr>')
for attrib in attribs:
f.write(u'<td>'+attrib+'</td>')
f.write(u'</tr>')
for attrib in attribs:
f.write(u'<td valign="top"><table border="1">')
for d in self.data[attrib]:
f.write(u'<tr><td>' + unicode(d[0]) + u'</td><td>' +unicode(d[1]) + u'</td></tr>')
f.write(u'</table></td>')
f.write(u'</tr></table>')
f.write(u'</body>')
f.close()
print "Saved to " + filename
def fetch_data(self, attribs):
for attrib in attribs:
self.data[attrib]=Counter(self.grep_data(attrib)).most_common()
def main():
global post_limit
global attrib_limit
fanpage_name = sys.argv[1]
attribs = sys.argv[2:]
f = FacebookFanAnalyzer(fanpage_name, post_limit, attribs, attrib_limit)
f.fetch_data(attribs)
f.save_as_html(attribs)
if __name__ == '__main__':
main()
Output:
Requesting 'comments' data: https://graph.facebook.com/cern/posts?limit=50&fields=comments.limit(50)&access_token=AjZCBe5yhAq2zFtyNS4tdPyhAq2zFtyNS4tdPw9sMkSUgBzF4tdPw9sMkSUgBzFZCDcd6asBpPndjhAq2zFtyNS4tsBphqfZBJNzx
Requesting 'likes' data: https://graph.facebook.com/cern/posts?limit=50&fields=likes.limit(50)&access_token=AjZCBe5yhAq2zFtyNS4tdPyhAq2zFtyNS4tdPw9sMkSUgBzF4tdPw9sMkSUgBzFZCDcd6asBpPndjhAq2zFtyNS4tsBphqfZBJNzx
Saved to cern.html
Read the list of posts on the page at the page's /feed connection and track the user IDs of those users who posted and commented on each post, building a list of who does it the most often.
Then store those somewhere and use the stored list in the part of your system which decides who to send the bonuses to.
e.g.
http://graph.facebook.com/cocacola/feed returns all the recent posts on the cocacola page, and you could track the IDs of the posters, commenters, likers, to determine who are the most active users
write a php or jquery script which is executed when user clicks like or share on your website just before actually sharing/like to fb and record the user info and the post he/she shared/liked. Now you can track who shared your post the most.
PHP/Jquery script will act as middle man, so dont use facebook share/like script directly. I will try to find the code I have written for this method. I have used PHP & Mysql. Try to use JQuery this will give a better result in terms of hidding the process (I mean data will be recorded without reloading the page).
Your question is nice, but it is quite hard.. (Actually, in the beginning, there's a thing that came from my mind that this is impossible. So, I build a quite different solution...) One of the best ways is to create a network where your viewers can register in the form that required the official URLs of their social networking pages, and also, they could choose that they doesn't have this kind of network:
“Do you want to share some of our page? Please register here first..”
So, they can get a specific URL that they've wanted to share when they're in your website, but they doesn't know the they're in tracing when they visited that specific URL.. (Every time a specific URL get visited, an I.P. get tracked and the number of visits get ++1 in a database.) Give them a dynamic URL on the top of your website that's in text area of every pages to track them. Or use scripting to automated the adding of a tracing query string on the URLs of your site.
I think there's a free software to build an affiliate network to make this easy! If your viewers really love your website, they'll registered to be an affiliate. But this thing is different, affiliate network is quite different from a network that mentioned in the paragraphs above..
But I think, you can also use Google Analytics to fully trace some referrals that didn't came from the URLs with dynamic QUERY STRING like Digital Point, but not from the other social network like Facebook 'cause you wouldn't get the exact Referral Paths with that kind of social network because of the query path. However you can use it to track the other networks. Also, AddThis Analytics is good for non-query string URLs.
The two kinds of referrals on Google Analytics are under of “Traffic Sources” menu of STANDARD REPORTS..
Traffic Sources
Sources
Referrals
Social
Network Referrals
This answer is pretty messy, but sometimes, quite useful.. Other than that? Please check these links below:
Publishing with an App Access Token - Facebook Developers
Facebook for Websites - Facebook Developers
Like - Facebook Developers
Open Graph Overview - Facebook Developers