After i click on Personal Image, an Sweetalert appear.
I want to upload image from input Swal() sweetAlert, but I always received null File in ActionResult.
I check it with a formData Send and never got actionresult request.
I working in MVC5 if someone can help me!! Thanks!!
Excuse me for my english.
Controller:
[LogActionFilter]
[HttpPost]
[ValidateAntiForgeryToken]
[MenuPermissions]
public ActionResult EditImage(HttpPostedFileBase inputImage)
{
//if (Request.Files.Count <= 0)
// return Json(new Dictionary<string, string>() { { "error", "Problemas en el servidor." } });
//var avatar = Request.Files[0];
var avatar = inputImage;
var userName = User.Identity.GetUserName();
if (Directory.Exists(Server.MapPath("~/Uploads/UserImg/")) == false)
{
Directory.CreateDirectory(Server.MapPath("~/Uploads/UserImg/"));
}
var path = Server.MapPath("~/Uploads/UserImg/" + userName + ".jpg");
avatar?.SaveAs(path);
return Json(new Dictionary<string, string>() { { "success", "Datos del usuario modificados satisfactoriamente." } });
}
View: Javascript
$("#AvatarId").click(function (eve) {
swal({
title: 'Selecciona tu imagen',
input: 'file',
inputAttributes: {
'accept': 'image/*',
'aria-label': 'Carga tu imagen de perfil',
'id': 'inputImage'
}
}).then(function (file) {
/*Ajax*/
var token = $('[name=__RequestVerificationToken]').val();
var Datos = {
__RequestVerificationToken: token,
Imagen: file
}
$.ajax({
url: "#Url.Action("EditImage", "Account")",
type: 'POST',
data: Datos,
success: function (data) {
if (data['success']) {
//var result = e.target.result;
//$('#AvatarIconId').attr("src", result);
swal("Lolazo","Hahaha","success");
} else {
var message = document.createTextNode(data['error']);
var p = $('#genericError')
p.empty();
p.append(message);
}
},error: function () {
var message = document.createTextNode('¡Ocurrió un error inesperado! Comuniquese con el proveedor del sistema.');
var p = $('#genericError')
p.empty();
p.append(message);
}
});
Related
This is my issue, I can access to MongoDB as an admin, but when I switch to “user” I can't, and it shows a message like this: msg: "You are not an admin!", even though I switched to 'user', this is and screenshot on MongoDB:
MongoDB, please click to see the image
This is a screenshot of the app message error:
Flutter app, please click to see the image
This is my code:
admin.js
const jwt = require("jsonwebtoken"); const User = require("../models/user");
const admin = async (req, res, next) => { try {
const token = req.header("x-auth-token");
if (!token)
return res.status(401).json({ msg: "No auth token, access denied" });
const verified = jwt.verify(token, "passwordKey");
if (!verified)
return res
.status(401)
.json({ msg: "Token verification failed, authorization denied." });
const user = await User.findById(verified.id);
if (user.type == "user" || user.type == "seller") {
return res.status(401).json({ msg: "You are not an admin!" });
}
req.user = verified.id;
req.token = token;
next(); } catch (err) {
res.status(500).json({ error: err.message }); } };
module.exports = admin;
admin_services.dart
class AdminServices {
void sellProduct({
required BuildContext context,
required String name,
required String description,
required double price,
required double quantity,
required String category,
required List<File> images,
}) async {
final userProvider = Provider.of<UserProvider>(context, listen: false);
try {
final cloudinary = CloudinaryPublic('blur', 'blur');
List<String> imageUrls = [];
for (int i = 0; i < images.length; i++) {
CloudinaryResponse res = await cloudinary
.uploadFile(CloudinaryFile.fromFile(images[i].path, folder: name));
imageUrls.add(res.secureUrl);
}
Product product = Product(
name: name,
description: description,
quantity: quantity,
images: imageUrls,
category: category,
price: price,
);
http.Response res = await http.post(
Uri.parse('$uri/admin/add-product'),
headers: {
'Content-Type': 'application/json; charset=UTF-8',
'x-auth-token': userProvider.user.token,
},
body: product.toJson(),
);
httpErrorHandle(
response: res,
context: context,
onSuccess: () {
showSnackBar(context, 'Product added successfully');
Navigator.pop(context);
},
);
} catch (e) {
showSnackBar(context, e.toString());
}
}
Future<List<Product>> fetchAllProducts(BuildContext context) async {
final userProvider = Provider.of<UserProvider>(context, listen: false);
List<Product> productList = [];
try {
http.Response res = await http.get(
Uri.parse('$uri/admnin/get-products'),
headers: {
'Content-Type': 'application/json; charset=UTF-8',
'x-auth-token': userProvider.user.token,
},
);
httpErrorHandle(
response: res,
context: context,
onSuccess: () {
for (int i = 0; i < jsonDecode(res.body).length; i++) {
productList.add(
Product.fromJson(
jsonEncode(
jsonDecode(res.body)[i],
),
),
);
}
});
} catch (e) {
showSnackBar(context, e.toString());
}
return productList;
}
void deleteProduct(
{required BuildContext context,
required Product product,
required VoidCallback onSuccess}) async {
final userProvider = Provider.of<UserProvider>(context, listen: false);
try {
http.Response res = await http.post(
Uri.parse('$uri/admnin/delete-product'),
headers: {
'Content-Type': 'application/json; charset=UTF-8',
'x-auth-token': userProvider.user.token,
},
body: jsonEncode(
{
'id': product.id,
},
),
);
httpErrorHandle(
response: res,
context: context,
onSuccess: () {
onSuccess();
},
);
} catch (e) {
showSnackBar(context, e.toString());
}
}
}
Hope you can help me, thanks for your attention
On the button click event of React side I am calling a node backend.
click event of react,
// calling node backend
this.uploadApi.command(postData.bin_files, this.dummy);
this.setState({submit_form});
}
dummy = (result)=>{
console.log(result);
}
This is my Node backend code,
import axios from 'axios';
class UploadFile {
constructor() {
this.url = 'http://localhost:56246/microservice/uploaddata'; //This is the local MVC application's URL (microservice is the controller)
}
command(postData, callback, uploadCallback = null) {
let jsonDataString = JSON.stringify(postData).replace(/&/g, '--and--');
jsonDataString = jsonDataString.replace(/\+/g, '--plus--');
const payload = JSON.parse(jsonDataString);
console.log('----------');
console.log(this.url);
console.log(payload);
console.log('----------');
// var data = qs.stringify({'jsondata':payload});
const data = new FormData();
for (var i = 0; i < payload.length; i++) {
console.log('inside for 1');
data.append(`model[${i}].name`, payload[i].name);
data.append(`model[${i}].bin_file`, payload[i].bin_file);
console.log('inside for 2');
}
console.log('=============');
console.log(data);
console.log('=============');
var config = {
method: 'post',
url: this.url,
headers: {
'Content-Type': 'multipart/form-data'
},
data: "jsondata=" + data,
onUploadProgress: (progressEvent) => {
const {
loaded,
total
} = progressEvent;
console.log("loaded:", loaded);
console.log("total:", total);
if (uploadCallback !== null) uploadCallback(progressEvent);
}
};
axios(config)
.then(function(response) {
// console.log(JSON.stringify(response.data));
callback(response.data);
})
.catch(function(error) {
console.log(error);
});
// axios.post(this.url, data)
// .then(res => console.log(res.data))
// .catch((error) => { console.error(error) });
}
}
export default UploadFile;
And this is my respective controller,
public dynamic UploadData(List<MemberInfo> model)
{
using (SqlConnection conn = new SqlConnection())
{
conn.ConnectionString = mstrDBConStringNew;
conn.Open();
SqlCommand command = new SqlCommand("SELECT * from tempstorage", conn);
using (SqlDataReader reader = command.ExecuteReader())
{
while (reader.Read())
{
//port = reader.GetString(0);
}
}
}
return "Hiiiiiiii";
}
public class MemberInfo
{
public string name { get; set; }
public string bin_file { get; set; }
}
Now If I show You while debugging, the controller and its respective action gets called but the value that I am expecting is null.
I have also tried like this way, but no luck
public dynamic UploadData(FormCollection model)
{
using (SqlConnection conn = new SqlConnection())
{
conn.ConnectionString = mstrDBConStringNew;
conn.Open();
SqlCommand command = new SqlCommand("SELECT * from tempstorage", conn);
using (SqlDataReader reader = command.ExecuteReader())
{
while (reader.Read())
{
//port = reader.GetString(0);
}
}
}
return "Hiiiiiiii";
}
This is my network request,
Please ask if anything additional is needed.
Yes I was able to figure out the issue,
var config = {
method: 'post',
url: this.url,
headers: {
'Content-Type': 'multipart/form-data'
},
data: data, // previously it was, "jsondata=" + data
Here I am getting the data as expected..
I am having issues with refreshing a partial view after post. what I want is to post some files, after they are uploaded I want to refresh a partial view. on a different partial view I delete the item and it refreshes ok, but on this partial it doesn't work. I got to some point were I can see that the refresh method is called before the AddImages and i still can't figure it out why the method is called and the data does not update.
I tried several methods here is where I am now :
Partial View-
<div id="UploadImages">
<form asp-page-handler="AddImages" id="imageUploadForm" method="post" data-ajax="true" data-ajax-method="post" data-ajax-update="#ProductImages">
<div class="card-body">
<h3>Edit Product Images</h3>
<input asp-for="#Model" multiple="multiple" id="ctl_images" name="upload_file" class="form-control" onchange="preview_image();" />
</div>
<button class="btn btn-sm btn-primary d-none d-md-inline-block" type="submit" id="AddImages" onclick="clickbtn();">
Add
</button>
</form>
<div id="image_preview">
</div>
</div>
Scripts to preview the uploaded image and to post to the razor page without refreshing the page, just the form:
<script>
//preview Images to upload.
function preview_image() {
total_file = document.getElementById("ctl_images").files.length;
for (var i = 0; i < total_file; i++) {
$('#image_preview').append("<span class=\"pip\">" +
"<img class='img-preview' id='previmg" + i + "'src='" + URL.createObjectURL(event.target.files[i]) + "'>"
+ "<br/><button class=\"btn-close\" aria-label='Close'></button>" + "</span>");
$('.btn-close').click(function () {
$(this).parent(".pip").remove();
$('#previmg' + i).click(function () { (this).remove(); });
});
}
}
//Load multiple Images to product catalog.
function clickbtn() {
var files = document.getElementById('ctl_images').files;
var url = window.location.pathname + "?handler=AddImages";
formData = new FormData();
for (var i = 0; i < files.length; i++) {
formData.append("CatalogImages", files[i]);
}
jQuery.ajax({
type: 'POST',
url: url,
data: formData,
cache: false,
contentType: false,
processData: false,
beforeSend: function (xhr) {
xhr.setRequestHeader("XSRF-TOKEN",
$('input:hidden[name="__RequestVerificationToken"]').val());
},
success: function () {
document.getElementById("imageUploadForm").reset();
var prv= document.getElementById("image_preview");
prv.innerHTML = "";
//if (repo.status == "success") {
// alert("File : " + repo.filename + " is uploaded successfully");
//}
},
error: function () {
alert("Error occurs");
},
});
}
Page model :
public async Task<IActionResult> OnPostAddImagesAsync()
{
var pathCtl = Path.Combine(_webHostEnvironment.WebRootPath, "Images/CatalogImages");
//if (!ModelState.IsValid)
// return Page();
//CatalogImages = (IFormFileCollection)Request.Form["ctl_Images"].ToList();
try
{
ProductImages = new List<ProductImageViewModel>();
foreach (var image in CatalogImages)
{
var uniqueFileName = string.Concat(Guid.NewGuid().ToString(), image.FileName);
using var fileStream = new FileStream(Path.Combine(pathCtl, uniqueFileName), FileMode.Create);
var productImage = new ProductImageViewModel
{
ImageUrl = Path.Combine("Images/CatalogImages", uniqueFileName),
ProductId = Product.Id,
};
await image.CopyToAsync(fileStream);
ProductImages.Add(productImage);
}
foreach (var item in ProductImages)
{
await _productImageRepo.Add(item, User);
}
var result = await OnPostRefreshImagesAsync(Product.Id);
return result;
}
catch (Exception ex)
{
_logger.LogError(ex.Message);
return Page();
throw ex;
}
}
public async Task<IActionResult> OnPostRefreshImagesAsync(int id)
{
var productImages = await _productImageRepo.GetByProductId(id);
var result = new PartialViewResult
{
ViewName = "~/Pages/Partials/_ProductImagesCardGroup.cshtml",
ViewData = new ViewDataDictionary<List<ProductImageViewModel>>(ViewData, productImages),
};
return result;
}
I ended up adding this code line to make it work. it seems posting questiosn here gives me inspiration.
$('#ProductImages').html(response);
//Load multiple Images to product catalog.
function clickbtn() {
var files = document.getElementById('ctl_images').files;
var url = window.location.pathname + "?handler=AddImages";
formData = new FormData();
for (var i = 0; i < files.length; i++) {
formData.append("CatalogImages", files[i]);
}
jQuery.ajax({
type: 'POST',
url: url,
data: formData,
cache: false,
contentType: false,
processData: false,
beforeSend: function (xhr) {
xhr.setRequestHeader("XSRF-TOKEN",
$('input:hidden[name="__RequestVerificationToken"]').val());
},
success: function (response) {
document.getElementById("imageUploadForm").reset();
var prv = document.getElementById("image_preview");
prv.innerHTML = "";
**$('#ProductImages').html(response);**
//if (repo.status == "success") {
// alert("File : " + repo.filename + " is uploaded successfully");
//}
},
error: function () {
alert("Error occurs");
},
});
I am trying to upload a profilePhoto from reactjs to express backend using FormData:
const form = new FormData();
form.append(user, "user");
form.append(profilePhoto, "profilePhoto");
axios({
method: "post",
url: "http://localhost:8082/candidate/addCandidate",
data: form,
headers: { "Content-Type": "multipart/form-data" },
})
.then(function (response) {
//handle success
console.log(response);
})
.catch(function (response) {
//handle error
console.log(response);
});
in the backend : (this works well with the postman and the image gets added to the backend)
const DIR = "./public/";
const storage = multer.diskStorage({
destination: (req, file, cb) => {
cb(null, DIR);
},
filename: (req, file, cb) => {
const fileName = file.originalname.toLowerCase().split(" ").join("-");
cb(null, uuid() + "-" + fileName);
},
});
var upload = multer({
storage: storage,
fileFilter: (req, file, cb) => {
if (
file.mimetype === "image/png" ||
file.mimetype === "image/jpg" ||
file.mimetype === "image/jpeg"
) {
cb(null, true);
} else {
cb(null, false);
return cb(new Error("Only .png, .jpg and .jpeg format allowed!"));
}
},
});
router.post(
"/addCandidate",
upload.single("profilePhoto"),
(req, res, next) => {
const url = req.protocol + "://" + req.get("host");
// try {
const candidate = new Candidate({
user: req.body.user,
profilePhoto: url + "/public/" + req.file,
});
candidate
.save()
.then((result) => {
console.log("bbbbbbbbbbbb", req);
res.status(201).json({
message: "User registered successfully!",
profilePhoto: result.profilePhoto,
});
})
.catch((err) => {
console.log("aaaaaaaaaaaa", req.body.file);
res.status(500).json({ error: err });
console.log(err);
});
}
);
however, when ever i try to upload a file it doesnt get uploaded to the backend and i get req.file undefined. I tried to console the req and this is what i get body:
{'606aee02f057cd714db2b646': 'user', '[object File]': 'profilePhoto'}
Any help!
I use something like this, you can change it for your project
My component:
import React from "react";
import ConfigX from '../ConfigX'
class FileUploader extends React.Component
{
url_upload = "";
url_download = "";
apiKey = "";
typ = "news";
typ_id = 99999;
constructor(props)
{
super(props)
this.state = {
view: "list",
title: "wybierz plik",
files: [],
uploadProcentAll: 10,
}
this.url_upload = ConfigX.restApi + "/rest,file_upload";
this.url_download = ConfigX.restApi + "/rest,file_list";
this.url_delete = ConfigX.restApi + "/rest,file_delete";
this.apiKey = this.props.apiKey;
this.typ = this.props.typ;
this.typ_id = this.props.typ_id;
}
/**
* Get actual list of file uploaded to server
*/
componentDidMount()
{
var dataPost = {
};
fetch( this.url_download , {
method: 'POST',
body: JSON.stringify(dataPost),
headers: {
'Content-Type': 'text/html',
'X-API-KEY': this.apiKey
}
})
.then( res => res.json() )
.then(json => {
// this.setState({
// files: json
// });
});
}
onChangeInput(event)
{
var handle = event.target;
console.log("FileUploader, selected: " + handle.files.length );
if( handle.files.length == 0) return false;
for(var i = 0; i < handle.files.length; i++)
{
var file = handle.files[i];
var isAdded = false;
this.state.files.forEach( exFile => {
if(exFile.name == file['name']) isAdded = true;
});
if(isAdded) continue;
var randName = crypto.getRandomValues( new Uint32Array(1)) + file['name'];
var item = {
name: file['name'],
progress: 0,
status: 'start',
uq: randName
}
var list = this.state.files;
list.push(item);
this.setState({ files: list});
this.startUpload(file, list.length-1, randName );
}
}
onDelete(event)
{
var uq = event.target.getAttribute("uq");
console.log("FileUploader, delete: " + uq);
var dataPost = {
uq: uq
};
fetch( this.url_delete , {
method: 'POST',
body: JSON.stringify(dataPost),
headers: {
'Content-Type': 'text/html',
'X-API-KEY': this.apiKey
}
})
.then( res => res.json() )
.then(json => {
if(json.status == "OK") //deleted on server..
{
var files = this.state.files.filter( item => {
if(item.uq == uq) return false;
return true;
} );
this.setState({
files: files
})
}
});
}
refreshProgress()
{
var sumP = 0;
var countP = 0;
this.state.files.map( item => {
if(item.status == 'start' || item.status == 'upload')
{
countP++;
sumP += item.progress;
}
} );
var avg = sumP / countP;
this.setState({
uploadProcentAll: avg
});
}
startUpload(file, tabIndex, randName)
{
var refState = this.state;
var refRefreshProgress = this.refreshProgress.bind(this);
var xhr = new XMLHttpRequest();
xhr.upload.addEventListener('progress',function(ev)
{
var procent = (ev.loaded/ev.total );
procent *= 100;
procent = Math.round(procent) ;
refState.files[tabIndex]['progress'] = procent;
refState.files[tabIndex]['status'] = "upload";
refRefreshProgress();
}, false)
xhr.addEventListener("load", function(ev){
} , false);
xhr.addEventListener("error", function(ev){}, false);
xhr.addEventListener("abort", function(ev){}, false);
xhr.onreadystatechange = function(ev)
{
if (xhr.readyState == 4)
{
refState.files[tabIndex]['status'] = "finish";
refState.files[tabIndex]['progress'] = 100;
}
};
xhr.open('POST', this.url_upload, true);
xhr.setRequestHeader('X-API-KEY', this.apiKey);
var data = new FormData();
data.append('file'+tabIndex, file );
data.append('typ', this.typ);
data.append('typ_id', this.typ_id);
data.append('fileUploader','yes');
data.append('uq', randName);
xhr.send(data);
}
render()
{
var progress = "";
var progressStyle = {
width: this.state.uploadProcentAll+"%"
}
if(this.state.uploadProcentAll > 0 && this.state.uploadProcentAll < 100 )
{
progress = (
<div className="progressBar">
<div className="progressLine" style={progressStyle}>{this.state.uploadProcentAll}</div>
</div>
)
}
return (
<div className="fileUploader">
<div className="buttonUploader">
<input type="file" onchange="zaladuj_pliki(this)" multiple id="fileselect" name="fileselect[]" accept="*/*" onChange={this.onChangeInput.bind(this)} />
{progress}
</div>
<table>
{
this.state.files.map( (item,index) => {
return (
<tr key={index} >
<td>{item.progress}</td>
<td>{item.name}</td>
<td uq={item.uq} onClick={this.onDelete.bind(this) } >Del</td>
</tr>
)
})
}
</table>
</div>
)
}
}
export default FileUploader;
Put in parent:
<FileUploader typ="sk_szkolenia" typ_id={this.state.rows.id} apiKey={this.props.apiKey} />
I'm confused as how I use the refresh token service. In my app there is a section with many playlists. When the user clicks on the playlist it runs this code:
func checkAuth() {
print("checking auth")
let auth = SPTAuth.defaultInstance()
//print(auth!.session.isValid())
if auth!.session == nil {
print("no auth")
if auth!.hasTokenRefreshService {
print("refresh token if session == nil")
self.renewTokenAndShowPlayer()
return
} else {
self.performSegue(withIdentifier: "LoginControllerSegue", sender: nil)
}
return
}
if auth!.session.isValid() && firstLoad {
// It's still valid, show the player.
print("valid auth")
self.showPlayer()
return
}
if auth!.hasTokenRefreshService {
print("refresh token")
self.renewTokenAndShowPlayer()
return
}
}
func renewTokenAndShowPlayer() {
SPTAuth.defaultInstance().renewSession(SPTAuth.defaultInstance().session) { error, session in
SPTAuth.defaultInstance().session = session
if error != nil {
print("Refreshing token failed.")
print("*** Error renewing session: \(error)")
self.performSegue(withIdentifier: "LoginControllerSegue", sender: nil)
return
}
self.showPlayer()
}
}
So let's say the user hasn't logged in yet and they goto the login player, then get authenticated.
Later, when they close the player and click on a different playlist, they are brought to the login screen again. Why is this?
I believe my refresh token service works, because whenever it is called after someone logs in, my server get's a /swap 200. Also, this only calls whenever someone comes back to the app (to the LoginViewController) after logging into Spotify, why is this?
Here is the code for my login page:
import UIKit
import WebKit
class LoginViewController: UIViewController, SPTStoreControllerDelegate, WebViewControllerDelegate {
#IBOutlet weak var statusLabel: UILabel!
var authViewController: UIViewController?
var firstLoad: Bool!
var Information: [String:String]?
override func viewDidLoad() {
super.viewDidLoad()
self.statusLabel.text = ""
self.firstLoad = true
let auth = SPTAuth.defaultInstance()
NotificationCenter.default.addObserver(self, selector: #selector(self.sessionUpdatedNotification), name: NSNotification.Name(rawValue: "sessionUpdated"), object: nil)
// Check if we have a token at all
if auth!.session == nil {
self.statusLabel.text = ""
return
}
// Check if it's still valid
if auth!.session.isValid() && self.firstLoad {
// It's still valid, show the player.
print("View did load, still valid, showing player")
self.showPlayer()
return
}
// Oh noes, the token has expired, if we have a token refresh service set up, we'll call tat one.
self.statusLabel.text = "Token expired."
print("Does auth have refresh service? \(auth!.hasTokenRefreshService)")
if auth!.hasTokenRefreshService {
print("trying to renew")
self.renewTokenAndShowPlayer()
return
}
// Else, just show login dialog
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
}
override var prefersStatusBarHidden: Bool {
return true
}
func getAuthViewController(withURL url: URL) -> UIViewController {
let webView = WebViewController(url: url)
webView.delegate = self
return UINavigationController(rootViewController: webView)
}
func sessionUpdatedNotification(_ notification: Notification) {
self.statusLabel.text = ""
let auth = SPTAuth.defaultInstance()
self.presentedViewController?.dismiss(animated: true, completion: { _ in })
if auth!.session != nil && auth!.session.isValid() {
self.statusLabel.text = ""
print("Session updated, showing player")
self.showPlayer()
}
else {
self.statusLabel.text = "Login failed."
print("*** Failed to log in")
}
}
func showPlayer() {
self.firstLoad = false
self.statusLabel.text = "Logged in."
self.Information?["SpotifyUsername"] = SPTAuth.defaultInstance().session.canonicalUsername
OperationQueue.main.addOperation {
[weak self] in
self?.performSegue(withIdentifier: "ShowPlayer", sender: self)
}
//self.performSegue(withIdentifier: "ShowPlayer", sender: nil)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "ShowPlayer" {
if let destination = segue.destination as? PlayController {
destination.Information = self.Information
}
}
}
internal func productViewControllerDidFinish(_ viewController: SPTStoreViewController) {
self.statusLabel.text = "App Store Dismissed."
viewController.dismiss(animated: true, completion: { _ in })
}
func openLoginPage() {
self.statusLabel.text = "Logging in..."
let auth = SPTAuth.defaultInstance()
if SPTAuth.supportsApplicationAuthentication() {
self.open(url: auth!.spotifyAppAuthenticationURL())
} else {
// storyboard?.instantiateViewController(withIdentifier: <#T##String#>)
//
self.authViewController = self.getAuthViewController(withURL: SPTAuth.defaultInstance().spotifyWebAuthenticationURL())
self.definesPresentationContext = true
self.present(self.authViewController!, animated: true, completion: { _ in })
}
}
func open(url: URL) {
if #available(iOS 10, *) {
UIApplication.shared.open(url, options: [:],
completionHandler: {
(success) in
print("Open \(url): \(success)")
})
} else {
let success = UIApplication.shared.openURL(url)
print("Open \(url): \(success)")
}
}
func renewTokenAndShowPlayer() {
self.statusLabel.text = "Refreshing token..."
print("trying to renew")
SPTAuth.defaultInstance().renewSession(SPTAuth.defaultInstance().session) { error, session in
SPTAuth.defaultInstance().session = session
if error != nil {
self.statusLabel.text = "Refreshing token failed."
print("*** Error renewing session: \(error)")
return
}
print("refreshed token")
self.presentedViewController?.dismiss(animated: true, completion: { _ in })
self.showPlayer()
}
}
func webViewControllerDidFinish(_ controller: WebViewController) {
// User tapped the close button. Treat as auth error
print("UI Web view did finish")
let auth = SPTAuth.defaultInstance()
// Uncomment to turn off native/SSO/flip-flop login flow
//auth.allowNativeLogin = NO;
// Check if we have a token at all
if auth!.session == nil {
self.statusLabel.text = ""
return
}
// Check if it's still valid
if auth!.session.isValid() && self.firstLoad {
// It's still valid, show the player.
print("Still valid, showing player")
self.showPlayer()
return
}
}
#IBAction func loginButtonWasPressed(_ sender: SPTConnectButton) {
self.openLoginPage()
}
#IBAction func showSpotifyAppStoreClicked(_ sender: UIButton) {
self.statusLabel.text = "Presenting App Store..."
let storeVC = SPTStoreViewController(campaignToken: "your_campaign_token", store: self)
self.present(storeVC!, animated: true, completion: { _ in })
}
#IBAction func clearCookiesClicked(_ sender: UIButton) {
let storage = HTTPCookieStorage.shared
for cookie: HTTPCookie in storage.cookies! {
if (cookie.domain as NSString).range(of: "spotify.").length > 0 || (cookie.domain as NSString).range(of: "facebook.").length > 0 {
storage.deleteCookie(cookie)
}
}
UserDefaults.standard.synchronize()
self.statusLabel.text! = "Cookies cleared."
}
#IBAction func dismissViewController () {
self.dismiss(animated: true, completion: {})
}
}
And here is my node.js code:
var spotifyEndpoint = 'https://accounts.spotify.com/api/token';
/**
* Swap endpoint
*
* Uses an authentication code on req.body to request access and
* refresh tokens. Refresh token is encrypted for safe storage.
*/
app.post('/swap', function (req, res, next) {
var formData = {
grant_type : 'authorization_code',
redirect_uri : clientCallback,
code : req.body.code
},
options = {
uri : url.parse(spotifyEndpoint),
headers : {
'Authorization' : authorizationHeader
},
form : formData,
method : 'POST',
json : true
};
console.log("Options" + options);
request(options, function (error, response, body) {
if (response.statusCode === 200) {
body.refresh_token = encrpytion.encrypt(body.refresh_token);
} else {
console.log("error swapping: " + error);
}
res.status(response.statusCode);
res.json(body);
});
});
app.post('/refresh', function (req, res, next) {
if (!req.body.refresh_token) {
res.status(400).json({ error : 'Refresh token is missing from body' });
return;
}
var refreshToken = encrpytion.decrypt(req.body.refresh_token),
formData = {
grant_type : 'refresh_token',
refresh_token : refreshToken
},
options = {
uri : url.parse(spotifyEndpoint),
headers : {
'Authorization' : authorizationHeader
},
form : formData,
method : 'POST',
json : true
};
request(options, function (error, response, body) {
if (response.statusCode === 200 && !!body.refresh_token) {
body.refresh_token = encrpytion.encrypt(body.refresh_token);
}
res.status(response.statusCode);
res.json(body);
});
});
The LoginViewController is only skipped after I log in once, are shown the player, quit the app, then start the app again and click on a song. Why is this?
(Note, this is a error I get from refreshing token: *** Error renewing session: Optional(Error Domain=com.spotify.auth Code=400 "No refresh token available in the session!" UserInfo={NSLocalizedDescription=No refresh token available in the session!}))
I got my refresh code from [this] project. Is Heroku necessary?