I'm implementing a feature on a project where we want users to be able to share a post on discord. Implementing sharing on facebook or twitter was easy using https://react-native-community.github.io/react-native-share/docs/share-single
But there's no support for discord on shareSingle and I don't want a share button calling for Native Share menu which could link to discord, I want a discord icon redirecting directly to discord. But I can't even find a way to open discord app with url schemas or universal link to trigger the app (discord:// or discord://discord or discordapp:// ...).
I tried to find a way to get access to native sharing in order to open discord sharing singly, but couldn't find a way.
Does anyone implemented discord sharing and have any tips on how to achieve that in react-native ?
You can make a fork the project and add this files:
android/src/main/java/cl/json/social/DiscordShare.java
package cl.json.social;
import android.content.ActivityNotFoundException;
import android.content.Intent;
import java.io.File;
import android.os.Environment;
import android.net.Uri;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReadableMap;
public class DiscordShare extends SingleShareIntent {
private static final String PACKAGE = "com.discord";
private static final String PLAY_STORE_LINK = "https://play.google.com/store/apps/details?id=com.discord";
public DiscordShare(ReactApplicationContext reactContext) {
super(reactContext);
}
#Override
public void open(ReadableMap options) throws ActivityNotFoundException {
super.open(options);
// extra params here
this.openIntentChooser();
}
#Override
protected String getPackage() {
return PACKAGE;
}
#Override
protected String getDefaultWebLink() {
return null;
}
#Override
protected String getPlayStoreLink() {
return PLAY_STORE_LINK;
}
}
Edit android/src/main/java/cl/json/RNShareModule.java
package cl.json;
// ...
import cl.json.social.DiscordShare;
public class RNShareModule extends ReactContextBaseJavaModule implements ActivityEventListener {
// ...
private enum SHARES {
facebook,
generic,
pagesmanager,
twitter,
whatsapp,
instagram,
instagramstories,
googleplus,
email,
pinterest,
messenger,
snapchat,
sms,
linkedin,
discord; // ADDED
public static ShareIntent getShareClass(String social, ReactApplicationContext reactContext) {
SHARES share = valueOf(social);
switch (share) {
case generic:
return new GenericShare(reactContext);
case facebook:
return new FacebookShare(reactContext);
case pagesmanager:
return new FacebookPagesManagerShare(reactContext);
case twitter:
return new TwitterShare(reactContext);
case whatsapp:
return new WhatsAppShare(reactContext);
case instagram:
return new InstagramShare(reactContext);
case instagramstories:
return new InstagramStoriesShare(reactContext);
case googleplus:
return new GooglePlusShare(reactContext);
case email:
return new EmailShare(reactContext);
case pinterest:
return new PinterestShare(reactContext);
case sms:
return new SMSShare(reactContext);
case snapchat:
return new SnapChatShare(reactContext);
case messenger:
return new MessengerShare(reactContext);
case linkedin:
return new LinkedinShare(reactContext);
case discord:
return new DiscordShare(reactContext); // ADDED
default:
return null;
}
}
};
}
// ...
Finally edit index.js
//...
class RNShare {
//...
static Social = {
FACEBOOK: NativeModules.RNShare.FACEBOOK || 'facebook',
FACEBOOK_STORIES: NativeModules.RNShare.FACEBOOK_STORIES || 'facebook-stories',
PAGESMANAGER: NativeModules.RNShare.PAGESMANAGER || 'pagesmanager',
TWITTER: NativeModules.RNShare.TWITTER || 'twitter',
WHATSAPP: NativeModules.RNShare.WHATSAPP || 'whatsapp',
INSTAGRAM: NativeModules.RNShare.INSTAGRAM || 'instagram',
INSTAGRAM_STORIES: NativeModules.RNShare.INSTAGRAM_STORIES || 'instagramstories',
GOOGLEPLUS: NativeModules.RNShare.GOOGLEPLUS || 'googleplus',
EMAIL: NativeModules.RNShare.EMAIL || 'email',
PINTEREST: NativeModules.RNShare.PINTEREST || 'pinterest',
LINKEDIN: NativeModules.RNShare.LINKEDIN || 'linkedin',
SMS: NativeModules.RNShare.SMS || 'sms',
DISCORD: NativeModules.RNShare.DISCORD || 'discord', // ADDED
};
// ...
}
In your project use:
Share.shareSingle({
title: 'test',
message: 'hola mundo',
url: 'https://json.cl',
social: Share.Social.DISCORD,
})
.then((res) => {
console.log(res);
})
.catch((err) => {
err && console.log(err);
});
Result:
Related
In this section of docs not all use-cases of guard usage explained clearly:
NestJS Docs - Claims-based authorization
CaslAbilityFactory implemented for these use-cases:
Admins can manage (create/read/update/delete) all entities
Users have read-only access to everything
Users can update their articles (article.authorId === userId)
Articles that are published already cannot be removed (article.isPublished === true)
and explained only the most trivial use-case:
Users have read-only access to everything
It's demonstrated with this controller method:
#Get()
#UseGuards(PoliciesGuard)
#checkPolicies((ability: AppAbility) => ability.can(Action.Read, Article))
findAll() {
return this.articlesService.findAll();
}
but how should I annotate a method to check the 3rd or 4th use-cases:
Articles that are published already cannot be removed:
(article.isPublished === true)
#Delete()
#UseGuards(PoliciesGuard)
#checkPolicies(?????????????????????????????)
delete(#Body() article: Article) {
return this.articlesService.delete(article.id);
}
Is it possible, at all? For this requirement PoliciesGuard or handler declared in #checkPolicies should be able to access method arguments.
How can controller method arguments be accessed from a guard?
Of course a workaround solution if you call ability.can(...) directly from controller method:
#Delete()
#UseGuards(SomeGuards but NOT PoliciesGuard)
delete(#Body() article: Article) {
const ability = this.caslAbilityFactory.createForUser(<<user from request>>);
if (!ability.can(Action.Delete, article)) {
throw new UnauthorizedException();
}
return this.articlesService.delete(article.id);
}
But this solution doesn't fit the original declarative pattern.
You can achieve this in the PolicyGuard. This is mentioned in NestJS docs here
your policy guard will be like this
#Injectable()
export class PoliciesGuard extends RequestGuard implements CanActivate {
public constructor(private reflector: Reflector, private caslAbilityFactory: CaslAbilityFactory) {
super();
}
public async canActivate(context: ExecutionContext): Promise<boolean> {
const policyHandlers = this.reflector.get<PolicyHandler[]>(CHECK_POLICIES_KEY, context.getHandler()) || [];
const request = this.getRequest(context);
const { user } = request;
const ability = await this.caslAbilityFactory.createForUser(user?.userId);
return policyHandlers.every(handler => this.execPolicyHandler(handler, ability, request));
}
private execPolicyHandler(handler: PolicyHandler, ability: AppAbility, request: Request) {
if (typeof handler === 'function') {
return handler(ability, request);
}
return handler.handle(ability, request);
}
}
then the checkPolicy will accept this function
export class ReadArticlePolicyHandler implements IPolicyHandler {
handle(ability: AppAbility, request) {
const { query } = request;
const article = new Article();
article.scope = query.scope;
return ability.can(Action.Read, article) || ability.can(Action.Delete, article);
}
}
I have next issue: my react-native app doesn't ask fb about all permissions from list, just about public_profile permission. System iOS.
My code is:
LoginManager.logInWithPermissions(['public_profile', 'user_friends', 'user_posts', 'email']).then(
(result) => {
if (result.isCancelled) {
alert('Login was cancelled')
} else {
console.log("RESULT_IS", result)
AccessToken.getCurrentAccessToken().then((data) => {
const accessToken = data.accessToken.toString();
const userID = data.userID.toString();
});
Profile.getCurrentProfile().then((data) => {
console.log('DATA', data);
})
}
},
);
console.log('DATA', data) shows that imageURL, userID and name has a value, and email, firstName, lastName, middleName are null.
console.log("RESULT_IS", result) shows RESULT_IS {"declinedPermissions": [], "grantedPermissions": ["public_profile"], "isCancelled": false}
So I am using Profile.getCurrentProfile() to get additional data from fb (for example email). To do that I asked fb about additional permissions adding them to LoginManager.logInWithPermissions(). As I understood my app doesn't ask about fb all permissions just about public_profile. Why does it happened and how can I fix it?
I had the same issue too.
On Android, in the path below
node_modules/react-native fbsdk-next/android/src/main/java/com/facebook/reactnative/androidsdk/FBProfileModule.java
You can import profile information right away by editing the file as shown below.
I also referenced other people's content.
So have a nice day!
FBProfileModule.java
package com.facebook.reactnative.androidsdk;
import com.facebook.Profile;
import com.facebook.ProfileTracker; // add
import com.facebook.react.bridge.Callback;
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.module.annotations.ReactModule;
import androidx.annotation.NonNull;
/**
* This is a {#link NativeModule} that allows JS to use FBSDKProfile info of the current logged user.
+ * current logged user // add
*/
#ReactModule(name = FBProfileModule.NAME)
public class FBProfileModule extends ReactContextBaseJavaModule {
public static final String NAME = "FBProfile";
private ProfileTracker mProfileTracker; // add
public FBProfileModule(ReactApplicationContext reactContext) {
super(reactContext);
}
#NonNull
#Override
public String getName() {
return NAME;
}
/**
* Get the current logged profile.
* #param callback Use callback to pass the current logged profile back to JS.
*/
#ReactMethod
public void getCurrentProfile(Callback callback) {
//Return the profile object as a ReactMap.
// add
if (Profile.getCurrentProfile() == null) {
mProfileTracker = new ProfileTracker() {
#Override
protected void onCurrentProfileChanged(Profile oldProfile, Profile currentProfile) {
callback.invoke(Utility.profileToReactMap(currentProfile));
mProfileTracker.stopTracking();
}
};
} else {
callback.invoke(Utility.profileToReactMap(Profile.getCurrentProfile()));
}
// remove
// callback.invoke(Profile.getCurrentProfile() == null
// ? null
// : Utility.profileToReactMap(Profile.getCurrentProfile()));
}
}
Facebook provides public profile by default if you want anything else you will have to add it by visiting your app in facebook developer console.
Go to your app
Open app Review
In app review open Permissions and Features
In Permissions and Features you can see multiple options
Select your desired permission and try again you will get that value as well.
I hope it helps you.
I am having an issue with react-native-gesture-handler. Whenever I link my react-native-gesture-handler to my project it stops working and shows this error. But after unlinking react-native-gesture-handler from my project the application work fine. But as I need to navigate from several screens, I need gesture handler.
First I thought it was the problem of the react-native version as I was using react-native version 0.57.0 but it's not working on 0.58.0 and 0.55.4 either.
package com.swmansion.gesturehandler.react;
import android.os.Build;
import android.view.View;
import android.view.ViewGroup;
import com.facebook.react.uimanager.PointerEvents;
import com.facebook.react.uimanager.ReactPointerEventsView;
import com.facebook.react.views.view.ReactViewGroup;
import com.swmansion.gesturehandler.PointerEventsConfig;
import com.swmansion.gesturehandler.ViewConfigurationHelper;
public class RNViewConfigurationHelper implements ViewConfigurationHelper {
#Override
public PointerEventsConfig getPointerEventsConfigForView(View view) {
PointerEvents pointerEvents;
pointerEvents = view instanceof ReactPointerEventsView ?
((ReactPointerEventsView) view).getPointerEvents() :
PointerEvents.AUTO;
// Views that are disabled should never be the target of pointer events. However, their children
// can be because some views (SwipeRefreshLayout) use enabled but still have children that can
// be valid targets.
if (!view.isEnabled()) {
if (pointerEvents == PointerEvents.AUTO) {
return PointerEventsConfig.BOX_NONE;
} else if (pointerEvents == PointerEvents.BOX_ONLY) {
return PointerEventsConfig.NONE;
}
}
switch (pointerEvents) {
case BOX_ONLY: return PointerEventsConfig.BOX_ONLY;
case BOX_NONE: return PointerEventsConfig.BOX_NONE;
case NONE: return PointerEventsConfig.NONE;
}
return PointerEventsConfig.AUTO;
}
#Override
public View getChildInDrawingOrderAtIndex(ViewGroup parent, int index) {
if (parent instanceof ReactViewGroup) {
return parent.getChildAt(((ReactViewGroup) parent).getZIndexMappedChildIndex(index));
}
return parent.getChildAt(index);
}
#Override
public boolean isViewClippingChildren(ViewGroup view) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2 && !view.getClipChildren()) {
if (view instanceof ReactViewGroup) {
String overflow = ((ReactViewGroup) view).getOverflow();
return "hidden".equals(overflow);
}
return false;
}
return true;
}
}
You can try manual linking.
Also check this issue out :
https://github.com/kmagiera/react-native-gesture-handler/issues/205
If you get the problem in Android, but not iOS, it could be that you need to add a polyfill for symbols. I can't remember where I found this, but I have used it in my own projects and it works. Just stick it in your index.js:
if (Platform.OS === 'android') {
if (typeof Symbol === 'undefined') {
if (Array.prototype['##iterator'] === undefined) {
Array.prototype['##iterator'] = function() {
let i = 0;
return {
next: () => ({
done: i >= this.length,
value: this[i++]
})
};
};
}
}
}
Is proper way to declare model class like java and how to pass this into second screen in react native?
export default class UserModel {
stateName;
username;
email;
mobile;
gender;
address;
constructor() {}
setStateName(stateName) {
this.stateName = stateName;
}
setUserName(username) {
this.username = username;
}
setEmail(email) {
this.email = email;
}
setMobile(mobile) {
this.mobile = mobile;
}
setGender(gender) {
this.gender = gender;
}
setAddress(address) {
this.address = address;
}
}
Step 1: Make UserModel.js
class UserModel {
constructor() {
stateName,
username,
email,
mobile,
gender,
address;
}
}
Note: Do not Export it if you don't want to set globally.
Step 2 : Screen1.js - Set UserModel and pass from screen1.
_handlePress = async () => {
UserModel.username = "Vishal Patoliya"
this.props.navigation.navigate('UserList',{userData: UserModel});
}
Step 3 : Receiving model class at another screen.
render() {
console.log(TAG, "render() Called.")
const UserModel = this.props.navigation.getParam('userData');
console.log("Username", UserModel.username)
}
OutPut :
01-16 17:30:32.085 4541 5638 I ReactNativeJS: 'Username', 'Vishal Patoliya'
Edit:
After some discussion, this was required answer:
this.props.navigation.navigate('UserList', { userModel: userModel });
this.props.getParam('userModel', /* optional default value */);
I assume this is your UserModel.js.
Now you are able to import the model like other components:
import UserModel from './location/UserModel';
But if you do it like this, you'd have to instanciate UserModel every time you import it.
If you'd like to prevent this, just instanciate a UserModel and export it inside the UserModel.js and import the instance anywhere.
Like this:
class UserModel {
//...
}
export default new UserModel();
other way might be:
export class UserModel {
//...
}
const GlobalUserModel = new UserModel();
export default GlobalUserModel;
to choose in other files what to import:
import { UserModel } from './location/UserModel'; //get new instance
or
import GlobalUserModel from './location/UserModel'; //get global instance
If imported via { UserModel }, you have to instanciate first: new UserModel()
...or vice versa.
Can I use recaptcha with apache wicket 1.5.3? Is there some good example?
In terms of Google reCAPTCHA v2, you can just follow its instruction, which is straightforward.
First of all, go to Google reCAPTCHA, and register your application there. Then you can work on the client and server sides respectively as below:
On the client side (see ref)
First, paste the snippet below <script...></script> before the closing tag on your HTML template, for example:
<script src='https://www.google.com/recaptcha/api.js'></script>
</head>
Then paste the snippet below <div...></div> at the end of the where you want the reCAPTCHA widget to appear, for example:
<div class="g-recaptcha" data-sitekey="{your public site key given by Google reCAPTCHA}"></div>
</form>
That's all on the client side.
On the server side (see ref)
When a user submits the form, you need to get the user response token from the g-recaptcha-response POST parameter. Then use the token, together with the secret key given by Google reCAPTCHA, and optional with the user's IP address, and then POST a request to the Google reCAPTCHA API. You'll then get the response from Google reCAPTHA, indicating whether the form verification succeeds or fails.
Below is the sample code on the server side.
User summits a Wicket form (Wicket 6 in this example):
protected void onSubmit() {
HttpServletRequest httpServletRequest = (HttpServletRequest)getRequest().getContainerRequest();
boolean isValidRecaptcha = ReCaptchaV2.getInstance().verify(httpServletRequest);
if(!isValidRecaptcha){
verificationFailedFeedbackPanel.setVisible(true);
return;
}
// reCAPTCHA verification succeeded, carry on handling form submission
...
}
ReCaptchaV2.java (Just Java, web framework independent)
import javax.servlet.http.HttpServletRequest;
import org.apache.log4j.Logger;
import org.codehaus.jackson.map.ObjectMapper;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;
public class ReCaptchaV2 {
private final static Logger logger = Logger.getLogger(ReCaptchaV2.class);
private final static String VERIFICATION_URL = "https://www.google.com/recaptcha/api/siteverify";
private final static String SECRET = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
private static ReCaptchaV2 instance = new ReCaptchaV2();
private ReCaptchaV2() {}
public static ReCaptchaV2 getInstance() {
return instance;
}
private boolean verify(String recaptchaUserResponse, String remoteip) {
boolean ret = false;
if (recaptchaUserResponse == null) {
return ret;
}
RestTemplate rt = new RestTemplate();
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
MultiValueMap<String, String> map= new LinkedMultiValueMap<String, String>();
map.add("secret", SECRET);
map.add("response", recaptchaUserResponse);
if (remoteip != null) {
map.add("remoteip", remoteip);
}
HttpEntity<MultiValueMap<String, String>> httpEntity = new HttpEntity<MultiValueMap<String, String>>(map, headers);
ResponseEntity<String> res = null;
try {
res = rt.exchange(VERIFICATION_URL, HttpMethod.POST, httpEntity, String.class);
} catch (Exception e) {
logger.error("Exception: " + e.getMessage());
}
if (res == null || res.getBody() == null) {
return ret;
}
Response response = null;
try {
response = new ObjectMapper().readValue(res.getBody(), Response.class);
} catch (Exception e) {
logger.error("Exception: " + e.getMessage());
}
if (response != null && response.isSuccess()) {
ret = true;
}
logger.info("Verification result: " + ret);
return ret;
}
public boolean verify(HttpServletRequest httpServletRequest) {
boolean ret = false;
if (httpServletRequest == null) {
return ret;
}
String recaptchaUserResponse = httpServletRequest.getParameter("g-recaptcha-response");
String remoteAddr = httpServletRequest.getRemoteAddr();
return verify(recaptchaUserResponse, remoteAddr);
}
}
Response.java (Java POJO)
public class Response {
private String challenge_ts;
private String hostname;
private boolean success;
public Response() {}
public String getChallenge_ts() {
return challenge_ts;
}
public void setChallenge_ts(String challenge_ts) {
this.challenge_ts = challenge_ts;
}
public String getHostname() {
return hostname;
}
public void setHostname(String hostname) {
this.hostname = hostname;
}
public boolean isSuccess() {
return success;
}
public void setSuccess(boolean success) {
this.success = success;
}
#Override
public String toString() {
return "ClassPojo [challenge_ts = " + challenge_ts + ", hostname = " + hostname + ", success = " + success + "]";
}
}
Have you read this?
I have added the guide here in case page disappears.
Usage
We will create a panel called RecaptchaPanel. In order to use this component to your application all you'll have to do is this:
add(new RecaptchaPanel("recaptcha"));
and of course, add the component in your markup:
<div wicket:id="recaptcha"></div>
Implementation
Implementation is simple. All you have to do, is to follow several steps:
Add recaptcha dependency to your project
<dependency>
<groupid>net.tanesha.recaptcha4j</groupid>
<artifactid>recaptcha4j</artifactid>
<version>0.0.7</version>
</dependency>
This library hides the implementation details and expose an API for dealing with recaptcha service.
Create associated markup (RecaptchaPanel.html)
<wicket:panel><div wicket:id="captcha"></div></wicket:panel>
Create RecaptchaPanel.java
import net.tanesha.recaptcha.ReCaptcha;
import net.tanesha.recaptcha.ReCaptchaFactory;
import net.tanesha.recaptcha.ReCaptchaImpl;
import net.tanesha.recaptcha.ReCaptchaResponse;
/**
* Displays recaptcha widget. It is configured using a pair of public/private keys which can be registered at the
* following location:
*
* https://www.google.com/recaptcha/admin/create
* <br>
* More details about recaptcha API: http://code.google.com/apis/recaptcha/intro.html
*
* #author Alex Objelean
*/
#SuppressWarnings("serial")
public class RecaptchaPanel extends Panel {
private static final Logger LOG = LoggerFactory.getLogger(RecaptchaPanel.class);
#SpringBean
private ServiceProvider serviceProvider;
public RecaptchaPanel(final String id) {
super(id);
final ReCaptcha recaptcha = ReCaptchaFactory.newReCaptcha(serviceProvider.getSettings().getRecaptchaPublicKey(),
serviceProvider.getSettings().getRecaptchaPrivateKey(), false);
add(new FormComponent<void>("captcha") {
#Override
protected void onComponentTagBody(final MarkupStream markupStream, final ComponentTag openTag) {
replaceComponentTagBody(markupStream, openTag, recaptcha.createRecaptchaHtml(null, null));
}
#Override
public void validate() {
final WebRequest request = (WebRequest)RequestCycle.get().getRequest();
final String remoteAddr = request.getHttpServletRequest().getRemoteAddr();
final ReCaptchaImpl reCaptcha = new ReCaptchaImpl();
reCaptcha.setPrivateKey(serviceProvider.getSettings().getRecaptchaPrivateKey());
final String challenge = request.getParameter("recaptcha_challenge_field");
final String uresponse = request.getParameter("recaptcha_response_field");
final ReCaptchaResponse reCaptchaResponse = reCaptcha.checkAnswer(remoteAddr, challenge, uresponse);
if (!reCaptchaResponse.isValid()) {
LOG.debug("wrong captcha");
error("Invalid captcha!");
}
}
});
}
}
</void>
Things to notice:
ServiceProvider - is a spring bean containing reCaptcha configurations (public key and private key). These keys are different depending on the domain where your application is deployed (by default works for any key when using localhost domain). You can generate keys here: https://www.google.com/recaptcha/admin/create
The RecaptchaPanel contains a FormComponent, which allows implementing validate method, containing the validation logic.
Because reCaptcha use hardcoded values for hidden fields, this component cannot have multiple independent instances on the same page.
Maybe the xaloon wicket components can be a solution for you. They have a Recaptcha plugin.