Readdy Write  
0,00 €
Your View Money
Views: Count
Self 20% 0
Your Content 60% 0

Users by Links 0
u1*(Content+Views) 10% 0
Follow-Follower 0
s2*(Income) 5% 0

Count
Followers 0
Login Register as User

Code für Authorize, Antiforgery und Route mit Asp Core 5 mit React: Speichern und Lesen einer Seite

12.03.2021 (👁64403)

Code Asp Core 5 mit React: Speichern in API mit

Beispiel Code für Asp Core und React.

Asp Core Server Code

Der Code enthält den Asp Core Code für die Startup.cs und den Controller. Wichtig ist mir dabei, dass der Code für die Authorization und ValitdateAntiforgery in den API übernommen werden.

React Code

Der React Code zeigt wie die Daten vom Server über eine API abgeholt werden und wieder gespeichert werden.

React Edit Page

https://localhost:44315//33

 

React Edit Page

https://localhost:44315//33

 

Asp.Net Core Net5

Wichtig ist hierbei, dass die Schreibvorgänge im Server durch Authorize und ValidateAntiForgery geschützt sind.

        [HttpPut("Save/{id}")]  //*ok

        [Authorize]

        [ValidateAntiForgeryToken]

        public async Task<ActionResult<ApiArticleModel>> Save(int id, ApiArticleModel apiArticle)

        {

..

React Speichern

Gesendet werden die Daten von einer React  Seite über ein Api. Hier wird ebenfalls der Sicherheitstoken angebunden

 

    async send_Data_to_Api() {

        //------< send_Data_to_Api() >------

        console.log(this.state);

        //< get text >

        let element = document.getElementById('ctleditor_html');

        let editor_innerhtml = element.innerHTML;

        let text_of_htmleditor = element.innerText;

        let xsrfToken = this.getCookie('XSRF-TOKEN');   //*get AntiforgeryToken from Cookies

        if (xsrfToken == null) { alert("AntiforgeryToken is missing")};

        //</ get text >

 

        //--< prepare send >--

        const token = await authService.getAccessToken();

        const requestOptions = {

            method: 'PUT',

            headers: {

                'Content-Type': 'application/json',

                'Authorization': `Bearer ${token}`,

                'X-XSRF-TOKEN': xsrfToken       //*add antiforgerytoken in from Cookies into Header               

            },

            body: JSON.stringify(

                {

                    //< data to send >

                    idarticle: this.state.idarticle,

                    iduser: this.state.iduser,

                    title: this.state.title,

                    htmlcontent: editor_innerhtml,

                    textcontent: text_of_htmleditor,

                    folder: this.state.folder,

                    keywords: this.state.keywords,

                    //</ data to send >

                })

        };

        //--</ prepare send >--

        //< send >

        const response = await fetch('api/articles/save/' + this.state.idarticle, requestOptions); //*SEND DATA to save-API

        //</ send >

Validation Token in Startup.cs Asp Core

 

ValidationToken Platzhalter.

Mit services.AddAntiforgery wird ein Header vorbereitet, wenn eine Seite geöffnet wird

            //*AntiforgeryToken

            // Angular's default header name for sending the XSRF token.

            services.AddAntiforgery(options =>

            {

                options.HeaderName = "X-XSRF-TOKEN";

            });

Validation Token erzeugen

Der AntiforgeryToken wird bei allen Seiten als Cookie erzeugt, welche in notwendig sind zur Sicherung beim Server.

            //--< AntiForgery >--

            //*add in Configure(.. , IAntiforgery antiforgery)

            app.Use(next => context =>

            {

                string path = context.Request.Path.Value;

                string[] urlAreas = { "/api", "/swagger", "articles" };

                if (

                    string.Equals(path, "/", StringComparison.OrdinalIgnoreCase) ||

                    string.Equals(path, "/index.html", StringComparison.OrdinalIgnoreCase) ||

                    urlAreas.Any(urlAreas=>path.StartsWith(urlAreas))

                    )

                {

                    // The request token can be sent as a JavaScript-readable cookie,

                    // and Angular uses it by default.

                    var tokens = antiforgery.GetAndStoreTokens(context);

                    context.Response.Cookies.Append("XSRF-TOKEN", tokens.RequestToken,

                        new CookieOptions() {

                            HttpOnly = false ,

                            Secure=false,

                            IsEssential=true,

                            SameSite=SameSiteMode.Strict                       

                        });

                }

 

                return next(context);

            });

            //--</ AntiForgery >--

 

 

Routing

Dabei wird das Asp Core Routing mit Endpoint Pattern verwendet.

Wenn der ValidationToken falsch ist, kommt die Seite 400 zurück

 

            app.UseEndpoints(endpoints =>

            {

                endpoints.MapControllerRoute(

                name: "🏠",

                pattern: "🏠",

                defaults: new { controller = "Articles", action = "List" }

                );

                endpoints.MapControllerRoute(

                name: "📜",

                pattern: "📜",

                defaults: new { controller = "Articles", action = "List" }

                );

               

                endpoints.MapControllerRoute(

                name: "default",

                pattern: "{controller}/{action}/{id?}"   //Important! Add your [httpget("action/{id?}")] in controller

                );

                endpoints.MapRazorPages();

            });

 

            app.UseSpa(spa =>

            {

                spa.Options.SourcePath = "ClientApp";

 

                if (env.IsDevelopment())

                {

                    spa.UseReactDevelopmentServer(npmScript: "start");

                }

            });

Example Code

Asp Core .Net5 und React

Asp Core Startup.cs  in .Net5

using CodeDocu.Data;

using CodeDocu.Models;

using CodeDocu.Services;

using Microsoft.AspNetCore.Antiforgery;

using Microsoft.AspNetCore.Authentication;

using Microsoft.AspNetCore.Builder;

using Microsoft.AspNetCore.Hosting;

using Microsoft.AspNetCore.Http;

using Microsoft.AspNetCore.Identity.UI.Services;

using Microsoft.AspNetCore.SpaServices.ReactDevelopmentServer;

using Microsoft.EntityFrameworkCore;

using Microsoft.Extensions.Configuration;

using Microsoft.Extensions.DependencyInjection;

using Microsoft.Extensions.Hosting;

using System;

using System.Linq;      //*any

 

namespace CodeDocu

{

    public class Startup

    {

        public Startup(IConfiguration configuration)

        {

            Configuration = configuration;

        }

 

        public IConfiguration Configuration { get; }    //Interface

 

        // This method gets called by the runtime. Use this method to add services to the container.

        public void ConfigureServices(IServiceCollection services)

        {

            //--------< ConfigureServices() >--------

            services.AddDbContext<ApplicationDbContext>(options =>

                 options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));

                //Server=.\\sqlexpress;Database=codedocu_de;Trusted_Connection=True;MultipleActiveResultSets=true

 

            services.AddDatabaseDeveloperPageExceptionFilter();

 

            services.AddDefaultIdentity<ApplicationUser>(options => options.SignIn.RequireConfirmedAccount = true)

                .AddEntityFrameworkStores<ApplicationDbContext>();

 

            services.AddIdentityServer()

                .AddApiAuthorization<ApplicationUser, ApplicationDbContext>();

 

            //*AntiforgeryToken

            // Angular's default header name for sending the XSRF token.

            services.AddAntiforgery(options =>

            {

                options.HeaderName = "X-XSRF-TOKEN";

                //options.Cookie.Name = "X-XSRF-TOKEN";  //"X-CSRF-TOKEN-OurAppName";

                // Set Cookie properties using CookieBuilder properties†.

                //options.FormFieldName = "AntiforgeryFieldname";

                //options.HeaderName = "X-CSRF-TOKEN-HEADERNAME";

                //options.SuppressXFrameOptionsHeader = false;

            });

 

            services.AddAuthentication()

                .AddIdentityServerJwt();

 

            services.AddControllersWithViews();

 

 

            //-< Email Registration >

            services.AddTransient<IEmailSender, EmailSender>();

            services.Configure<AuthMessageSenderOptions>(Configuration);

            //-</ Email Registration >

 

            services.AddRazorPages();

 

            // In production, the React files will be served from this directory

            services.AddSpaStaticFiles(configuration =>

            {

                configuration.RootPath = "ClientApp/build";

            });

 

            //--------</ ConfigureServices() >--------

        }

 

 

 

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.

        //*Added Antiforgery: , IAntiforgery antiforgery

        public void Configure(IApplicationBuilder app, IWebHostEnvironment env, IAntiforgery antiforgery)

        {

            //--------< Configure() >--------

            if (env.IsDevelopment())

            {

                app.UseDeveloperExceptionPage();

                app.UseMigrationsEndPoint();

            }

            else

            {

                app.UseExceptionHandler("/Error");

                // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.

                app.UseHsts();

            }

 

            app.UseHttpsRedirection();

            app.UseStaticFiles();

            app.UseSpaStaticFiles();

 

            app.UseRouting();

 

            app.UseAuthentication();

            app.UseIdentityServer();

            app.UseAuthorization();

 

 

           

            //--< AntiForgery >--

            //*add in Configure(.. , IAntiforgery antiforgery)

            app.Use(next => context =>

            {

                string path = context.Request.Path.Value;

                string[] urlAreas = { "/api", "/swagger", "articles" };

                if (

                    string.Equals(path, "/", StringComparison.OrdinalIgnoreCase) ||

                    string.Equals(path, "/index.html", StringComparison.OrdinalIgnoreCase) ||

                    urlAreas.Any(urlAreas=>path.StartsWith(urlAreas))

                    )

                {

                    // The request token can be sent as a JavaScript-readable cookie,

                    // and Angular uses it by default.

                    var tokens = antiforgery.GetAndStoreTokens(context);

                    context.Response.Cookies.Append("XSRF-TOKEN", tokens.RequestToken,

                        new CookieOptions() {

                            HttpOnly = false ,

                            Secure=false,

                            IsEssential=true,

                            SameSite=SameSiteMode.Strict                       

                        });

                }

 

                return next(context);

            });

            //--</ AntiForgery >--

 

            app.UseEndpoints(endpoints =>

            {

                endpoints.MapControllerRoute(

                name: "🏠",

                pattern: "🏠",

                defaults: new { controller = "Articles", action = "List" }

                );

                endpoints.MapControllerRoute(

                name: "📜",

                pattern: "📜",

                defaults: new { controller = "Articles", action = "List" }

                );

               

                endpoints.MapControllerRoute(

                name: "default",

                pattern: "{controller}/{action}/{id?}"   //Important! Add your [httpget("action/{id?}")] in controller

                );

                endpoints.MapRazorPages();

            });

 

            app.UseSpa(spa =>

            {

                spa.Options.SourcePath = "ClientApp";

 

                if (env.IsDevelopment())

                {

                    spa.UseReactDevelopmentServer(npmScript: "start");

                }

            });

 

            //--------</ Configure() >--------

        }

    }

}

 

 

 

 

Asp Core ArticlesController.cs .Net5

using System;

using System.Collections.Generic;

using System.Linq;

using System.Threading.Tasks;

using Microsoft.AspNetCore.Http;

using Microsoft.AspNetCore.Authorization;

using Microsoft.AspNetCore.Mvc;

using Microsoft.EntityFrameworkCore;

using CodeDocu.Models;

 

namespace CodeDocu.Controllers

{

    //------------< Namespace >------------

 

    [Route("api/articles")]

    [ApiController]

    public class ArticlesController : ControllerBase

    {

        //--------< Controller: ArticlesController >--------

        #region init

        private readonly Data.ApplicationDbContext _dbContext;

 

        public ArticlesController(Data.ApplicationDbContext context)

        {

            _dbContext = context; //*get database context

        }

        #endregion /init

 

        // GET: api/Articles ============

        [Route("List")]

        [HttpGet]

        public async Task<ActionResult<IEnumerable<ApiArticleListModel>>> List()

        {

            //-------------< Liste: GetArticles >-------------

            //< get Data from SQL-Server >

            var query = new List<ArticleModel>();

            try

            {

                var data = _dbContext.tbl_Articles.Take(10);

                query = await data.ToListAsync();

            }

            catch (Exception err)

            {

                return BadRequest(err.Message);

            }

 

            //</ get Data from SQL-Server >

 

 

            //----< fill Data_to_Output >----📜📜📜

            List<ApiArticleListModel> dataList = new List<ApiArticleListModel>();

            //---< @Loop: Rows >---

            foreach (var row in query)

            {

                //--< Row to Data >--

                //< correct >

                string sShort = row.TextContent;

                if (sShort.Length > 255) { sShort = sShort.Substring(0, 255); }

 

                row.TextContent = sShort;

                //</ correct >

 

                //< Data >

                ApiArticleListModel item = new ApiArticleListModel();

                item.idarticle = row.IDArticle;

                item.title = row.Title;

                item.textcontent = sShort;

                item.folder = row.Folder;

                item.imagepath = "/User_Files/Articles/Images/Image_144_0_pad.jpg"; //*144 " + item.IDArticle + "

                //</ Data >

 

                //< add >

                dataList.Add(item);

                //</ add >

                //--</ Row to Data >--

            }

            //---</ @Loop: Rows >---

            //----</ fill Data_to_Output >----

 

 

            return dataList;

 

            //-------------</ Liste: GetArticles >-------------

        }

 

 

 

        // GET: api/Articles/5 ============👁👁👁

        // EventsController

        [HttpGet("Read/{id}")]

        public async Task<ActionResult<ApiArticleModel>> Read(long? id)

        {

            //-------------< Liste: GetArticles >-------------

            if (!(id > 0))

            {

                return NotFound();

            }

 

            long IDArticle = System.Convert.ToInt64(id);

 

            //--< Get User ID >--

            //internal referenz-Number for tracking in tables

            String sIDUser = Request.Headers["sub"];   //*ID in aspUsers wie: 1428ca0b-186c..

            //--</ Get User ID >--

 

            //--< Get Data >--

            var article = await _dbContext.tbl_Articles.SingleOrDefaultAsync(article => article.IDArticle == IDArticle);

            if (article == null)

            {

                return NotFound();  //:break

            }

            //--</ Get Data >--

 

            //----< fill Data_to_Output >----

            //< Data >

            ApiArticleModel apiArticle = new ApiArticleModel();

            apiArticle.idarticle = article.IDArticle;

            if (sIDUser == article.IDUser) { apiArticle.isowner = true; } else { apiArticle.isowner = false; }

            apiArticle.iduser = article.IDUser;

            apiArticle.title = article.Title;

            apiArticle.htmlcontent = article.HtmlContent;

            apiArticle.folder = article.Folder;

            apiArticle.keywords = article.Keywords;

            apiArticle.imagepath = "/User_Files/Articles/Images/Image_144_0_pad.jpg"; //*144 " + item.IDArticle + "

            //</ Data >

            //----</ fill Data_to_Output >----

 

 

            return apiArticle;           

            //-------------</ Liste: GetArticles >-------------

        }

 

 

 

 

 

 

        // PUT: api/tbl_Articles/5 ============== ✍✍✍

        [HttpPut("Save/{id}")]  //*ok

        //[HttpPut("{id}")]  //*ok

        [Authorize]

        [ValidateAntiForgeryToken]

        public async Task<ActionResult<ApiArticleModel>> Save(int id, ApiArticleModel apiArticle)

        {

            //int IDArticle = id;

            var test = Request.Path;

            // -------------< Edit_Postback() > -------------

            if (id != apiArticle.idarticle)

            {

                return BadRequest("Bad");

            }

 

            //--< Get User ID >--

            //internal referenz-Number for tracking in tables

            String sIDUser = User.getUserId();   //*ID in aspUsers wie: 1428ca0b-186c..

            if (sIDUser == "") return BadRequest();

            //--</ Get User ID >--

 

            //< get_database >

            ArticleModel article;

            if (id > 0)

            {

                article = await _dbContext.tbl_Articles.SingleOrDefaultAsync(a => a.IDArticle == id);    //#changed to async 09.02.2021

                if (article== null) { return Content("No Record found for ID=" + id); }

 

                //< check Owner >

                String IDOwner = article.IDUser;

                if (IDOwner != sIDUser) {

                   return StatusCode(StatusCodes.Status403Forbidden,"user is not owner.");

                }

                //</ check Owner >

            }

            else

            {

                article = new ArticleModel();

                article.IDUser = sIDUser;

            }

            //</ get_database >

 

 

            //----< Save Note-Data >----

            //< get >

            string sHTML = apiArticle.htmlcontent;

            string sTitle = apiArticle.title;

            string sFolder = apiArticle.folder;

            string sKeywords = apiArticle.keywords;

            //</ get >

 

 

 

            //< correct >

            //*SQL injection, script blocks..

            sTitle = Correct_Methods.correct_In_String_Strong(sTitle);

            sFolder = Correct_Methods.correct_In_String_Strong(sFolder);

            sKeywords  = Correct_Methods.correct_In_String_Strong(sKeywords);

            sHTML = Correct_Methods.correct_In_String_Minimal(sHTML);

            //</ correct >

 

            //< Convert >

            sHTML = Correct_Methods.replace_Text_To_Links(sHTML);

            sHTML = Correct_Methods.replace_Youtube(sHTML);

 

 

            string sText = Html_Methods.HTML_to_Text(sHTML);

            //</ Convert >

 

            //--< data >--

            //article.IDUser = *oben gesetzt

            article.Title = sTitle;

            article.HtmlContent = sHTML;

            article.TextContent = sText;

            article.Folder = sFolder;

            article.Keywords = sKeywords;

            apiArticle.isowner = true;

            article.DtEdit = DateTime.Now;

            //note.IsDraft = false;   //try allways on

            //--</ data >--

 

            try

            {

                if (id > 0)

                {

                    //< update Server >

                    _dbContext.Update(article);

                    //</ update Server >

                }

                else

                {

                    //< Add on Server >

                    _dbContext.tbl_Articles.Add(article);

                    _dbContext.SaveChanges();

                    id = article.IDArticle;

                    //</ Add on Server >

                }

                //await _dbContext.SaveChangesAsync(true);

            }

            catch (DbUpdateConcurrencyException)

            {

                return Content("Error in saving Note with ID=" + id);

            }

            //----</ Save Note-Data >----

 

 

            //----< Delete Images not in HTML >----

            //List<Note_Image_Model> list_Images = _dbContext.tbl_Notes_Images.Where(img => img.IDNote == IDNote).ToList();

            //foreach (Note_Image_Model image in list_Images)

            //{

            //    string sImage_BaseTag = "Image_" + IDNote + "_" + image.ImageNr;

            //    if (sHTML.IndexOf(sImage_BaseTag) < 0)

            //    {

 

            //        //< delete Image_sized >

            //        //--< Image >--

            //        string folder_Path_Images = _hostingEnvironment.WebRootPath + "\\User_Files\\Notes\\Images\\";

            //        File_Methods.Delete_File(folder_Path_Images + "\\" + sImage_BaseTag + "_mini.jpg");

            //        File_Methods.Delete_File(folder_Path_Images + "\\" + sImage_BaseTag + "_pad.jpg");

            //        File_Methods.Delete_File(folder_Path_Images + "\\" + sImage_BaseTag + "_blog.jpg");

            //        File_Methods.Delete_File(folder_Path_Images + "\\" + sImage_BaseTag + ".jpg");

            //        //</ delete Image_sized >

 

            //        _dbContext.tbl_Notes_Images.Remove(image);

            //    }

            //}

            //----</ Delete Images not in HTML >----

 

 

            //< save note+images >

            await _dbContext.SaveChangesAsync(true);

            //</ save note+images >

 

            //< load Output-Data >

            //ApiArticleModel apiData = new ApiArticleModel();

            apiArticle.idarticle = article.IDArticle;

            apiArticle.iduser = sIDUser; //#todo: check

            apiArticle.title = article.Title;

            apiArticle.htmlcontent =  article.HtmlContent;

            apiArticle.folder = article.Folder;

            apiArticle.keywords = article.Keywords;

            apiArticle.dtcreated = article.DtCreated;

            apiArticle.dtedit = article.DtEdit;

            //</ load Output-Data >

            // -------------</ Edit_Postback() > -------------

 

            return apiArticle;

        }

 

 

 

        [HttpGet("images/{id}")]

        public async Task<ActionResult<ApiArticleModel>> Images(long id)

        {

            Console.WriteLine("Images " + Request.Path);

            return new JsonResult(new { route = "Images" });

        }

 

 

 

            //----< Delete Images not in HTML >----

            //List<Note_Image_Model> list_Images = _dbContext.tbl_Notes_Images.Where(img => img.IDNote == IDNote).ToList();

            //foreach (Note_Image_Model image in list_Images)

            //{

            //    string sImage_BaseTag = "Image_" + IDNote + "_" + image.ImageNr;

            //    if (sHTML.IndexOf(sImage_BaseTag) < 0)

            //    {

 

            //        //< delete Image_sized >

            //        //--< Image >--

            //        string folder_Path_Images = _hostingEnvironment.WebRootPath + "\\User_Files\\Notes\\Images\\";

            //        File_Methods.Delete_File(folder_Path_Images + "\\" + sImage_BaseTag + "_mini.jpg");

            //        File_Methods.Delete_File(folder_Path_Images + "\\" + sImage_BaseTag + "_pad.jpg");

            //        File_Methods.Delete_File(folder_Path_Images + "\\" + sImage_BaseTag + "_blog.jpg");

            //        File_Methods.Delete_File(folder_Path_Images + "\\" + sImage_BaseTag + ".jpg");

            //        //</ delete Image_sized >

 

            //        _dbContext.tbl_Notes_Images.Remove(image);

            //    }

            //}

            //----</ Delete Images not in HTML >----

 

 

            //< save note+images >

            await _dbContext.SaveChangesAsync(true);

            //</ save note+images >

 

            //< load Output-Data >

            //ApiArticleModel apiData = new ApiArticleModel();

            apiArticle.idarticle = article.IDArticle;

            apiArticle.iduser = sIDUser; //#todo: check

            apiArticle.title = article.Title;

            apiArticle.htmlcontent =  article.HtmlContent;

            apiArticle.folder = article.Folder;

            apiArticle.keywords = article.Keywords;

            apiArticle.dtcreated = article.DtCreated;

            apiArticle.dtedit = article.DtEdit;

            //</ load Output-Data >

            // -------------</ Edit_Postback() > -------------

 

            return apiArticle;

        }

 

 

        [HttpGet("images/{id}")]

        public async Task<ActionResult<ApiArticleModel>> Images(long id)

        {

            Console.WriteLine("Images " + Request.Path);

            return new JsonResult(new { route = "Images" });

        }

 

 

 

 

 

 

        // DELETE: api/tbl_Articles/5

        [HttpDelete]

        //[HttpDelete("{id}")]

        public async Task<IActionResult> Delete(int id)

        {

            var tblContent = await _dbContext.tbl_Articles.FindAsync(id);

            if (tblContent == null)

            {

                return NotFound();

            }

 

            _dbContext.tbl_Articles.Remove(tblContent);

            await _dbContext.SaveChangesAsync();

 

            return NoContent();

        }

 

        private bool TblContentExists(int id)

        {

            return _dbContext.tbl_Articles.Any(e => e.IDArticle == id);

        }

        //----------</ Controller: ArticlesController >--------

    }

 

    //------------</ Namespace >------------

}

 

 

 

 

React Page: Edit.js

import React, { Component } from 'react';

import authService from './api-authorization/AuthorizeService'

import './Edit.css';

import "bootstrap/dist/css/bootstrap.min.css";

import Fab from '@material-ui/core/Fab';

import RemoveRedEye from '@material-ui/icons/RemoveRedEye';

import TextField from '@material-ui/core/TextField';

import { Link } from 'react-router-dom';

 

 

 

export class Edit extends Component {

    //--------< component: Article >--------

 

    //----< compontent >----

    baseURL = "/";

    id  = 0;

 

    constructor(props) {

        //-< react: parameter >

        super(props);

        //-</ react: parameter >

        //--< react: variables >--

        this.state = {

            idarticle: 0,

            iduser: "",

            isowner: false,

            title: "",

            textcontent: "",

            htmlcontent: "",

            folder: "",

            keywords: "",

            nimages: "",

            nvideos: "",

            nfiles: "",

            dtcreated: "",

            dtedit: "",

            loading: true,

            status: "",

            ok: true,

 

            token: "",

        }

 

        //this.onChangeEditor = this.onChangeEditor.bind(this);

        this.onClickSubmit = this.onClickSubmit.bind(this); //for using this.function() in component

    }

 

 

 

    //--< component.events >--

    async componentDidMount() {

        this.id = this.props.match.params.id;

        if (this.id > 0) {

            this.get_Data_from_Api(this.id);

        }

        else {

            this.setState({ loading: false });

        }

    }

    //--</ component.events >--

 

    //onChangeEditor() {

    //    var editor_innerHtml = document.getElementById("ctleditor_html").innerHTML;

    //    this.setState(state => ({

    //        editor_innerhtml: editor_innerHtml

    //    }));

    //}

 

    //----</ compontent >----

 

 

    //====< functions:Api >====

    onClickSubmit(event) {

        this.send_Data_to_Api();

        //window.location.href = '...'; //with history

        window.location.replace('/👁/' + this.state.idarticle); //*no back history       

    }

   // using jQuery

    getCookie(name) {

        let cookieValue = null;

        if (document.cookie && document.cookie !== '') {

            const cookies = document.cookie.split(';');

            for (let i = 0; i < cookies.length; i++) {

                const cookie = cookies[i].trim();

                // Does this cookie string begin with the name we want?

                if (cookie.substring(0, name.length + 1) === (name + '=')) {

                    cookieValue = decodeURIComponent(cookie.substring(name.length + 1));

                    break;

                }

            }

        }

        return cookieValue;

    }

 

    //*load data from web api

    async get_Data_from_Api(id) {

        //--------< populateData() >--------

        const user = await authService.getUser();

        const token = await authService.getAccessToken();

        const response = await fetch('api/articles/read/' + id, { 

            method: 'get',

            headers: !token ? {} : {

                'Authorization': `Bearer ${token}`,

               'sub': user.sub

            }

        });  

        const data = await response.json();             //*convert json to data

        //console.log("this.state=" + this.state);

        //console.log(this.state);

        if (data.isowner !== true)

        {

            this.props.history.goBack();

        }; 

       

 

        this.setState(state => ({

            idarticle: data.idarticle,

            iduser: data.iduser,

            isowner: data.isowner,

            title: data.title,

            htmlcontent: data.htmlcontent,

            folder: data.folder,

            keywords: data.keywords,

            nimages: data.nimages,

            nvideos: data.nvideos,

            nfiles: data.nfiles,

            dtcreated: data.dtcreated,

            dtedit: data.dtedit,

 

            loading: false,

        })); //*refresh state of arcticles

        //--------</ populateData() >--------

    }

 

    async send_Data_to_Api() {

        //------< send_Data_to_Api() >------

        console.log(this.state);

        //< get text >

        let element = document.getElementById('ctleditor_html');

        let editor_innerhtml = element.innerHTML;

        let text_of_htmleditor = element.innerText;

        let xsrfToken = this.getCookie('XSRF-TOKEN');   //*get AntiforgeryToken from Cookies

        if (xsrfToken == null) { alert("AntiforgeryToken is missing")};

        //</ get text >

 

        //--< prepare send >--

        const token = await authService.getAccessToken();

        const requestOptions = {

            method: 'PUT',

            headers: {

                'Content-Type': 'application/json',

                'Authorization': `Bearer ${token}`,

                'X-XSRF-TOKEN': xsrfToken       //*add antiforgerytoken in from Cookies into Header               

            },

            body: JSON.stringify(

                {

                    //< data to send >

                    idarticle: this.state.idarticle,

                    iduser: this.state.iduser,

                    title: this.state.title,

                    htmlcontent: editor_innerhtml,

                    textcontent: text_of_htmleditor,

                    folder: this.state.folder,

                    keywords: this.state.keywords,

                    //</ data to send >

                })

        };

        //--</ prepare send >--

        //< send >

        const response = await fetch('api/articles/save/' + this.state.idarticle, requestOptions); //*SEND DATA to save-API

        //</ send >

        if (response.status !== 200) {

            //-< error: sending >-

            if (response.status === 400) alert("400 Bad Data Request");

            else if (response.status === 401) alert("401 Unauthorized");

            else if (response.status === 403) alert("403 User is not Owner");

            else alert('send error ' + response.status);

            //-</ error: sending >-

        }

        else {

            //-< ok: sending result >-

            const data = await response.json();

            //*refresh return values

            this.setState({

                idarticle: data.idArticle,

                iduser: data.idUser,

                title: data.title,

                htmlcontent: data.htmlcontent,

                folder: data.folder,

                keywords: data.keywords,

 

                loading: false,

                status: "data ok"

            });

            //-</ ok: sending result >-

        }

        //------</ send_Data_to_Api() >------

    }

    //====</ functions:Api >====

 

    //====< HTML >====

    //----< render >----

    render() {

        //--------< render(HTML) >--------

 

        document.title = " " + this.state.title;

 

        return (

 

            //----< return >----     

            <div className="submit-form">

                {

                    //--< IsLoaded >--

                    <form className="submit-form">

                        <div>

 

                            {

                                this.state.loading===false && (

                                    //--< Buttons >--

                                    //#to={"/👁/" + this.state.idarticle}

                                    <Link onClick={this.onClickSubmit}>

                                        <Fab color="secondary" aria-label="save and show" style={{ float: 'right' }} >

                                            <RemoveRedEye />

                                        </Fab>

                                    </Link>

                                    //--</ Buttons >--

                                )

                            }

 

                            <div id="divHeadFields">

                            <div style={{ flexFlow: "row" }}>

                                <TextField

                                    id="ctlfolder"

                                    value={this.state.folder}

                                    label="Folder"

                                    type="text"

                                    placeholder="software/subject/.."

                                    autoComplete="true"

                                    color="primary"

                                    InputLabelProps={{

                                        shrink: true,

                                    }}

                                    onChange={(e) => { this.setState({ folder: e.target.value }) }}

                                    style={{ width: '45%', marginRight: '8px' }}

                                />

                                <TextField

                                    id="ctlkeywords"

                                    value={this.state.keywords}

                                    label="Keywords"

                                    type="text"

                                    placeholder="keyword;part1 part2.."

                                    autoComplete="true"

                                    color="primary"

                                    InputLabelProps={{

                                        shrink: true,

                                    }}

                                    onChange={(e) => { this.setState({ keywords: e.target.value }) }}

                                    style={{ width: '45%' }}

                                />

                            </div>

 

                            <TextField

                                id="ctltitle"

                                label="Title"

                                type="text"

                                placeholder="Title"

                                autoComplete="true"

                                required

                                fullWidth

                                color="primary"

                                InputLabelProps={{

                                    shrink: true,

                                }}

                                value={this.state.title}

                                onChange={(e) => {

                                    console.log(e.target.value);

                                    this.setState({ title: e.target.value })

                                }}

                                style={{ width: '100%', marginBotton: '10px',  }}

                                />

                                </div>

 

                            <div id="ctleditor_html" className="edit_texteditor"

                                contentEditable={true} suppressContentEditableWarning={true}

                                dangerouslySetInnerHTML={{ __html: this.state.htmlcontent }}

                            />

                              

 

                        </div>

 

                        <input type="hidden" value={this.state.idarticle} />

                    </form>

                    //--</ IsLoaded >--

                }

            </div>

            //----</ return >----

        );

        //--------</ render(HTML) >--------

    }

    //----</ render >----

 

    //====</ HTML >====

 

 

    //--------</ component: Articles >--------

}