How to get Facebook friends list in using Spring Social - spring

I am trying to get FB friends list. I know that it will return only those who also using the app.
I made REST point that should return friends list. Here is modified code for tests:
#RequestMapping(value = "/fbfriends",
method = RequestMethod.GET,
produces = MediaType.APPLICATION_JSON_VALUE)
#Timed
public List<User> GetFriends(Connection<?> connection) {
log.debug("REST request to get all Friends");
if (connection == null) {
log.error("Cannot create social user because connection is null");
throw new IllegalArgumentException("Connection cannot be null");
}
log.debug("Got connection");
List<Permission> permissions = facebook.userOperations().getUserPermissions();
log.debug("Permission size: " + permissions.size() + " Permission: " + permissions);
for (Permission perm: permissions){
log.debug(perm.getName() + " " + perm.getStatus());
}
List<User> friends = facebook.friendOperations().getFriendProfiles();
log.debug("Friends size: " + friends.size() + " Friends:" + friends.toString());
PagedList<Post> feed = facebook.feedOperations().getFeed();
log.debug("Feed size: " + feed.size() + " Feed: " + feed.toString());
PagedList<UserTaggableFriend> taggable = facebook.friendOperations().getTaggableFriends();
log.debug("Taggable size: " + friends.size() + " Taggable:" + friends.toString());
log.debug("Ho Ho Ho");
return friends;
}
All those log.debug just for me, here is the result:
2016-07-27 17:38:22.443 DEBUG 10828 --- [nio-8080-exec-1] c.m.myapp.aop.logging.LoggingAspect : Exit: org.springframework.social.connect.ConnectionRepository.findPrimaryConnection() with result = org.springframework.social.connect.support.OAuth2Connection#99deb877
2016-07-27 17:38:22.581 DEBUG 10828 --- [nio-8080-exec-1] c.m.myapp.web.rest.FbFriendResource : Permission size: 2 Permission: [org.springframework.social.facebook.api.Permission#8fbfe4, org.springframework.social.facebook.api.Permission#5328b7d2]
2016-07-27 17:38:22.581 DEBUG 10828 --- [nio-8080-exec-1] c.m.myapp.web.rest.FbFriendResource : email granted
2016-07-27 17:38:22.581 DEBUG 10828 --- [nio-8080-exec-1] c.m.myapp.web.rest.FbFriendResource : public_profile granted
2016-07-27 17:38:22.694 DEBUG 10828 --- [nio-8080-exec-1] c.m.myapp.web.rest.FbFriendResource : Friends size: 0 Friends:[]
2016-07-27 17:38:22.739 DEBUG 10828 --- [nio-8080-exec-1] c.m.myapp.web.rest.FbFriendResource : Feed size: 0 Feed: []
2016-07-27 17:38:22.788 DEBUG 10828 --- [nio-8080-exec-1] c.m.myapp.web.rest.FbFriendResource : Taggable size: 0 Taggable:[]
2016-07-27 17:38:22.789 DEBUG 10828 --- [nio-8080-exec-1] c.m.myapp.web.rest.FbFriendResource : Ho Ho Ho
2016-07-27 17:38:22.798 DEBUG 10828 --- [nio-8080-exec-1] c.m.myapp.aop.logging.LoggingAspect : Exit: com.mycompany.myapp.web.rest.FbFriendResource.GetFriends() with result = []
As you can see there is only two permissions granted: public_profile and email.
In some examples I found that permissions could be added:
I didn't found anything like this. In my App settings I found only this page under "App Review"
Here is user_friends "live and available for users"
What I did wrong or how to actually use this "granted by default" permission using Spring Social?
How can I ask for additional permissions like user_posts and use them in Spring Framework?

The solution for my problem was pretty simple. If someone has the same problems, permissions for the app defined in request to the FB at Facebook Login button.
Something like this depends on your case.
<fb:login-button scope="public_profile,email,user_friends" onlogin="checkLoginState();">
</fb:login-button>
Was new to this and just used sample code for login button without review and thoght that permissions defined at App settings.

Related

Spring WebFlux - WebGraphQlInterceptor has empty request data

I would need to retrieve data from query headers for use in the GraphQl query controller. I searched around a bit and found the WebGraphQlInterceptor, but realized that when the WebGraphQlRequest argument is invoked it is completely devoid of information.
For example, this code:
#Component
class WebRequestInterceptor : WebGraphQlInterceptor {
val logger: Logger by lazy { LoggerFactory.getLogger(WebRequestInterceptor::class.java) }
override fun intercept(request: WebGraphQlRequest, chain: WebGraphQlInterceptor.Chain): Mono<WebGraphQlResponse> {
logger.info("URI", request.uri.toString())
logger.info("HEADERS", request.headers.toString())
logger.info("DOCUMENT", request.document)
return chain.next(request)
}
}
Returns:
2022-09-12 10:57:11.747 INFO 1 --- [or-http-epoll-1] b.s.b.gateway.auth.WebRequestInterceptor : URI *empty string*
2022-09-12 10:57:11.748 INFO 1 --- [or-http-epoll-1] b.s.b.gateway.auth.WebRequestInterceptor : HEADERS *empty string*
2022-09-12 10:57:11.748 INFO 1 --- [or-http-epoll-1] b.s.b.gateway.auth.WebRequestInterceptor : DOCUMENT *empty string*
P.S. The same thing happens if I try to log a single headers element using the request.headers.getFirst(..) function.

Azure Spring Cloud AppConfiguration refresh is not working

im having some problems refreshing anything, be it #ConfigurationProperties or #Value, using the
implementation("com.azure.spring:azure-spring-cloud-appconfiguration-config:2.1.1")
library. From what i could find and debug, the inner AppConfigurationRefresh class is called and the RefreshEvent is created reacting correctly to changes done in Azure Config Server. Problem is that, when context is updated, there also should be new values recognized by the ContextRefresher, which is not the case for me.
Spring Boot ContextRefresher
public synchronized Set<String> refreshEnvironment() {
Map<String, Object> before = extract(this.context.getEnvironment().getPropertySources());
updateEnvironment();
Set<String> keys = changes(before, extract(this.context.getEnvironment().getPropertySources())).keySet();
this.context.publishEvent(new EnvironmentChangeEvent(this.context, keys));
return keys;
}
The result of that refresh method is always empty, which means no changes were found.
Logs generated by the refresh event:
2021-11-29 19:53:03.543 INFO [] 34820 --- [ task-2] c.a.s.c.config.AppConfigurationRefresh : Configuration Refresh Event triggered by /myprefix/my.config.value
2021-11-29 19:53:53.694 INFO [] 34820 --- [ task-2] b.c.PropertySourceBootstrapConfiguration : Located property source: [BootstrapPropertySource {name='bootstrapProperties-/application/https://my-config-store-stage.azconfig.io/dev'}]
2021-11-29 19:53:53.719 INFO [] 34820 --- [ task-2] o.s.boot.SpringApplication : The following profiles are active: messaging,db,dev
2021-11-29 19:53:53.736 INFO [] 34820 --- [ task-2] o.s.boot.SpringApplication : Started application in 3.347 seconds (JVM running for 158.594)
2021-11-29 19:54:01.265 INFO [] 34820 --- [ task-2] o.s.c.e.event.RefreshEventListener : Refresh keys changed: []
2021-11-29 19:54:03.553 INFO [] 34820 --- [ scheduling-1] d.l.d.a.s.c.AppConfigurationUpdater : All configurations were refreshed.
bootstrap.yml
spring:
cloud:
azure:
appconfiguration:
stores:
- connection-string: ${connection-string}
selects:
- key-filter: '/myprefix/'
label-filter: dev
monitoring:
enabled: true
refresh-interval: 1s
triggers:
-
label: dev
key: /myprefix/my.config.value
I only noticed one thing that could be relevant to this, looking at log from start of the application (where everything is loaded properly) and at the point of refresh:
2021-11-29 19:51:31.578 INFO [] 34820 --- [ main] b.c.PropertySourceBootstrapConfiguration : Located property source: [BootstrapPropertySource {name='bootstrapProperties-/myprefix/https://my-config-store-stage.azconfig.io/dev'}, BootstrapPropertySource {name='bootstrapProperties-/application/https://my-config-store-stage.azconfig.io/dev'}]
2021-11-29 19:53:53.694 INFO [] 34820 --- [ task-2] b.c.PropertySourceBootstrapConfiguration : Located property source: [BootstrapPropertySource {name='bootstrapProperties-/application/https://my-config-store-stage.azconfig.io/dev'}]
It seems that when refreshing, the Spring is not able to locate all BootstrapPropertySources and maybe thats why there are no changes found. Am i missing some configuration somewhere to specify these or does anyone know whats the problem here. Thanks
The Problem
The changed values in azure appconfig store are triggering refresh event (either automaticaly using "web" version of library or through manual call to AppConfigurationRefresh.refreshConfigurations) and you can see it in the logs like this:
2021-11-29 19:53:03.543 INFO [] 34820 --- [ task-2] c.a.s.c.config.AppConfigurationRefresh : Configuration Refresh Event triggered by /myprefix/my.config.value
2021-11-29 19:53:53.694 INFO [] 34820 --- [ task-2] b.c.PropertySourceBootstrapConfiguration : Located property source: [BootstrapPropertySource {name='bootstrapProperties-/application/https://my-config-store-stage.azconfig.io/dev'}]
2021-11-29 19:53:53.719 INFO [] 34820 --- [ task-2] o.s.boot.SpringApplication : The following profiles are active: messaging,db,dev
2021-11-29 19:53:53.736 INFO [] 34820 --- [ task-2] o.s.boot.SpringApplication : Started application in 3.347 seconds (JVM running for 158.594)
2021-11-29 19:54:01.265 INFO [] 34820 --- [ task-2] o.s.c.e.event.RefreshEventListener : Refresh keys changed: []
However the Spring Boot is unable to locate any changes in PropertySources as is evident from:
2021-11-29 19:54:01.265 INFO [] 34820 --- [ task-2] o.s.c.e.event.RefreshEventListener : Refresh keys changed: []
The Research
What actually was deciding factor for me to find the issue, was indeed the difference between the found BootstrapPropertySources at the start of the application and at the refresh.
2021-11-29 19:51:31.578 INFO [] 34820 --- [ main] b.c.PropertySourceBootstrapConfiguration : Located property source: [BootstrapPropertySource {name='bootstrapProperties-/myprefix/https://my-config-store-stage.azconfig.io/dev'}, BootstrapPropertySource {name='bootstrapProperties-/application/https://my-config-store-stage.azconfig.io/dev'}]
2021-11-29 19:53:53.694 INFO [] 34820 --- [ task-2] b.c.PropertySourceBootstrapConfiguration : Located property source: [BootstrapPropertySource {name='bootstrapProperties-/application/https://my-config-store-stage.azconfig.io/dev'}]
The culprit for the not found changes is indeed the missing BootstrapPropertySource at the update. From my testing its evident, that all configuration properties are dependant on the name of the PropertySource they came from and if its missing, they will retain their original old value.
The problem is in the way the appconfig library is locating/creating the BootstrapPropertySources and does not differentiate between startup and update.
The following code is from appconfiguration library and i only took the part that is causing the bug.
public final class AppConfigurationPropertySourceLocator implements PropertySourceLocator {
...
#Override
public PropertySource<?> locate(Environment environment) {
...
String applicationName = this.properties.getName();
if (!StringUtils.hasText(applicationName)) {
applicationName = env.getProperty(SPRING_APP_NAME_PROP);
}
...
}
...
}
The problem here is that env.getProperty(SPRING_APP_NAME_PROP); is filled with "spring.application.name" during startup, because spring loads all .yml files at once, but is not available during update. Also the AppConfigurationProperties properties.name is never mentioned in any documentation from azure, but is crutial to overcome this problem.
The Solution
If you are using custom spring.application.name include some name also into the bootstrap.yml like this:
spring:
cloud:
azure:
appconfiguration:
name: your-name #any value will work
stores:
- connection-string: ${connection-string}
selects:
- key-filter: '/myprefix/'
label-filter: dev
monitoring:
enabled: true
refresh-interval: 1s
triggers:
-
label: dev
key: /myprefix/my.config.value
This will make the library use the properties name value at all times and avoid usage of the problematic spring.application.name value.
You should be using "com.azure.spring:azure-spring-cloud-appconfiguration-config-web:2.1.1" if you want to enable auto refresh. Otherwise you have to manually trigger refresh using AzureCloudConfigRefresh's refreshConfiguration. See: https://github.com/Azure/azure-sdk-for-java/tree/main/sdk/appconfiguration/azure-spring-cloud-starter-appconfiguration-config#configuration-refresh
As for the ContextRefresher, is it inside of the refresh scope? If not then the values are unable to be changed.
Though looking at your logs you don't seem to be picking up the changes. Can you take a look at this demo?
https://github.com/Azure-Samples/azure-spring-boot-samples/tree/main/appconfiguration/azure-appconfiguration-refresh-sample
The instructions to run it are here https://github.com/Azure-Samples/azure-spring-boot-samples/pull/106/files

SQL Error: 900 when running update query with multiple fields

Running JPA native query with multiple fields from SQL developer console works, but the same query results in SQL Error: 900, SQLState: 42000 from JPA repository.
Query in JPA -
#Query(value = "UPDATE SUBSCRIPTIONFILE SET DESCRIPTION = ?1, FILENAME = ?2, VERSION = ?3 WHERE (PLATFORM = ?4 AND PRODUCTSKU = ?5)", nativeQuery = true)
SUBSCRIPTIONFILE updateUsingEmbdedKey(String DESCRIPTION, String FILENAME, String VERSION, String PLATFORM, String PRODUCTSKU);
And as the debug console shows -
2018-12-03 18:37:02.734 DEBUG 5180 --- [ main] org.hibernate.SQL : UPDATE SUBSCRIPTIONFILE SET DESCRIPTION = ?, FILENAME = ?, VERSION = ? WHERE (PLATFORM = ? AND PRODUCTSKU = ?)
2018-12-03 18:37:04.405 TRACE 5180 --- [ main] o.h.type.descriptor.sql.BasicBinder : binding parameter [1] as [VARCHAR] - [newDescription!]
2018-12-03 18:37:04.427 TRACE 5180 --- [ main] o.h.type.descriptor.sql.BasicBinder : binding parameter [2] as [VARCHAR] - [bla bla bla]
2018-12-03 18:37:04.437 TRACE 5180 --- [ main] o.h.type.descriptor.sql.BasicBinder : binding parameter [3] as [VARCHAR] - [bla]
2018-12-03 18:37:04.445 TRACE 5180 --- [ main] o.h.type.descriptor.sql.BasicBinder : binding parameter [4] as [VARCHAR] - [xyz]
2018-12-03 18:37:04.455 TRACE 5180 --- [ main] o.h.type.descriptor.sql.BasicBinder : binding parameter [5] as [VARCHAR] - [testSave]
My questions:
1 - is the query syntax is OK?
2- is there a better way to do it using a built-in JpaRepository query?
Entire JpaRepository -
public interface SubscriptionRepo extends JpaRepository<SUBSCRIPTIONFILE, SUBSCRIPTIONFILE_KEY>{
#Query(value = "UPDATE SUBSCRIPTIONFILE SET DESCRIPTION = ?1, FILENAME = ?2, VERSION = ?3 WHERE (PLATFORM = ?4 AND PRODUCTSKU = ?5)", nativeQuery = true)
SUBSCRIPTIONFILE updateUsingEmbdedKey(String DESCRIPTION, String FILENAME, String VERSION, String PLATFORM, String PRODUCTSKU);
}
Since this is an update you need a #Modifying annotation to go with your #Query annotation.

Why does my FlywayMigrationStrategy call afterMigrate.sql twice?

I work on a Spring-boot project and use Flyway for database migration.
While working in dev-profile I want to fill the database with dummy data.
In order to have the exact same initial data values I overrode the FlywayMigrationStrategy Bean so that it performs a flyway.clean() before the migration starts:
#Bean
#Profile("dev")
public FlywayMigrationStrategy cleanMigrateStrategy() {
FlywayMigrationStrategy strategy = new FlywayMigrationStrategy() {
#Override
public void migrate(Flyway flyway) {
flyway.clean();
flyway.migrate();
}
};
return strategy;
}
My Migration folder contains several versioned migration scripts and ONE afterMigrate callback script which adds data to the created Tables.
The problem now is, the afterMigrate.sql script gets called two times as you can see from the following log:
2017-07-03 13:12:42.332 INFO 23222 --- [ main] o.f.core.internal.command.DbClean : Successfully cleaned schema "PUBLIC" (execution time 00:00.031s)
2017-07-03 13:12:42.397 INFO 23222 --- [ main] o.f.core.internal.command.DbValidate : Successfully validated 4 migrations (execution time 00:00.044s)
2017-07-03 13:12:42.413 INFO 23222 --- [ main] o.f.c.i.metadatatable.MetaDataTableImpl : Creating Metadata table: "PUBLIC"."schema_version"
2017-07-03 13:12:42.428 INFO 23222 --- [ main] o.f.core.internal.command.DbMigrate : Current version of schema "PUBLIC": << Empty Schema >>
2017-07-03 13:12:42.430 INFO 23222 --- [ main] o.f.core.internal.command.DbMigrate : Migrating schema "PUBLIC" to version 1 - create users
2017-07-03 13:12:42.449 INFO 23222 --- [ main] o.f.core.internal.command.DbMigrate : Migrating schema "PUBLIC" to version 2 - create address
2017-07-03 13:12:42.464 INFO 23222 --- [ main] o.f.core.internal.command.DbMigrate : Migrating schema "PUBLIC" to version 3 - create patient case
2017-07-03 13:12:42.475 INFO 23222 --- [ main] o.f.core.internal.command.DbMigrate : Migrating schema "PUBLIC" to version 4 - state machine
2017-07-03 13:12:42.498 INFO 23222 --- [ main] o.f.core.internal.command.DbMigrate : Successfully applied 4 migrations to schema "PUBLIC" (execution time 00:00.086s).
2017-07-03 13:12:42.499 INFO 23222 --- [ main] o.f.c.i.c.SqlScriptFlywayCallback : Executing SQL callback: afterMigrate
2017-07-03 13:12:42.502 INFO 23222 --- [ main] o.f.c.i.c.SqlScriptFlywayCallback : Executing SQL callback: afterMigrate
2017-07-03 13:12:42.917 INFO 23222 --- [ main] o.s.j.e.a.AnnotationMBeanExporter : Registering beans for JMX exposure on startup
If I remove the flyway.clean() function call it gets called only once.
Can somebody tell me why its called twice when I call flyway.clean() and flyway.migrate() and how to prevent the second call?
It's a known issue which will be fixed in Flyway 5.0. See https://github.com/flyway/flyway/issues/1653

Spock test - RESTClient: HttpResponseException: Not Found

I want to write a test for a GET request when the API returns 404.
My test:
def "Should return 404 - object deleted before"() {
setup:
def advertisementEndpoint = new RESTClient( 'http://localhost:8080/' )
when:
def resp = advertisementEndpoint.get(
path: 'api/advertisement/1',
contentType: groovyx.net.http.ContentType.JSON
)
then:
resp.status == 404
}
My error:
14:24:59.294 [main] DEBUG o.a.h.impl.client.DefaultHttpClient -
Connection can be kept alive indefinitely 14:24:59.305 [main] DEBUG
groovyx.net.http.RESTClient - Response code: 404; found handler:
org.codehaus.groovy.runtime.MethodClosure#312aa7c 14:24:59.306 [main]
DEBUG groovyx.net.http.RESTClient - Parsing response as:
application/json 14:24:59.443 [main] DEBUG org.apache.http.wire - <<
"ba[\r][\n]" 14:24:59.444 [main] DEBUG org.apache.http.wire - <<
"{"timestamp":1436358299234,"status":404,"error":"Not
Found","exception":"com.pgssoft.exparo.web.ResourceNotFoundException","message":"No
message available","path":"/api/advertisement/1"}" 14:24:59.445 [main]
DEBUG org.apache.http.wire - << "[\r][\n]" 14:24:59.445 [main] DEBUG
org.apache.http.wire - << "0[\r][\n]" 14:24:59.446 [main] DEBUG
org.apache.http.wire - << "[\r][\n]" 14:24:59.446 [main] DEBUG
o.a.h.i.c.BasicClientConnectionManager - Releasing connection
org.apache.http.impl.conn.ManagedClientConnectionImpl#2ab4bc72
14:24:59.446 [main] DEBUG o.a.h.i.c.BasicClientConnectionManager -
Connection can be kept alive indefinitely 14:24:59.449 [main] DEBUG
groovyx.net.http.RESTClient - Parsed data to instance of: class
groovy.json.internal.LazyMap
groovyx.net.http.HttpResponseException: Not Found at
groovyx.net.http.RESTClient.defaultFailureHandler(RESTClient.java:263)
at groovy.lang.Closure.call(Closure.java:423) at
groovyx.net.http.HTTPBuilder$1.handleResponse(HTTPBuilder.java:503)
at
org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:218)
at
org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:160)
at groovyx.net.http.HTTPBuilder.doRequest(HTTPBuilder.java:515) at
groovyx.net.http.RESTClient.get(RESTClient.java:119) at
AdvertisementTest.Should return 404 - object delete
before(AdvertisementTest.groovy:79)
You need a failure handler for the underlying HTTPBuilder. From the HTTPBuilder javadoc:
You can also set a default response handler called for any status code
399 that is not matched to a specific handler. Setting the value outside a request closure means it will apply to all future requests
with this HTTPBuilder instance:
http.handler.failure = { resp ->
println "Unexpected failure: ${resp.statusLine}" }
Therefore:
#Grapes(
#Grab(group='org.codehaus.groovy.modules.http-builder', module='http-builder', version='0.7.1')
)
import groovyx.net.*
import groovyx.net.http.*
def restClient = new RESTClient('http://localhost/wrong')
restClient.handler.failure = { resp -> resp.status }
def response = restClient.get([:])
assert response == 404

Resources