Ajout de l'E2E #10

Merged
Shikiryu merged 3 commits from e2e into master 2020-03-16 17:06:09 +01:00
8 changed files with 186 additions and 85 deletions

View File

@ -11,8 +11,6 @@ use DateTime;
use Illuminate\Http\UploadedFile;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Redirect;
use Intervention\Image\Constraint;
use Intervention\Image\Facades\Image;
class DashboardController extends Controller
{
@ -37,6 +35,7 @@ class DashboardController extends Controller
setlocale(LC_TIME, 'fr_FR.utf8');
$today = new DateTime();
$user_id = Auth::user()->getAuthIdentifier();
$user = \App\User::find($user_id);
$all_counts = Post::where('user_id', $user_id)->count();
$year_counts = Post::where('user_id', $user_id)->whereYear('date_post', $today->format('Y'))->count();
$month_counts = Post::where('user_id', $user_id)
@ -57,6 +56,7 @@ class DashboardController extends Controller
return view('home', [
'already' => $already,
'must_encrypt' => $user->encrypt_messages,
'all_counts' => $all_counts,
'year_counts' => $year_counts,
'month_counts' => $month_counts,

View File

@ -0,0 +1,32 @@
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class UpdateUsersEncryption extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('users', function (Blueprint $table) {
$table->boolean('encrypt_messages')->default(true);
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('users', function (Blueprint $table) {
$table->removeColumn('encrypt_messages');
});
}
}

View File

@ -24,7 +24,9 @@
"vue-template-compiler": "^2.6.10"
},
"dependencies": {
"endcrypt": "^1.2.3",
"tabler-ui": "^0.0.34",
"textarea-caret": "^3.1.0"
"textarea-caret": "^3.1.0",
"vue2-storage": "^4.0.5"
}
}

127
resources/js/app.js vendored
View File

@ -27,41 +27,104 @@ window.Vue = require('vue');
* or customize the JavaScript scaffolding to fit your unique needs.
*/
import App from './components/App.vue';
import Vue from 'vue';
import Autocomplete from './components/Autocomplete.vue';
import {Endcrypt} from 'endcrypt';
import {Vue2Storage} from 'vue2-storage';
const e = new Endcrypt();
// You can specify the plug-in configuration when connecting, passing the second object to Vue.use
Vue.use(Vue2Storage, {
prefix: 'journal_',
driver: 'session',
ttl: 60 * 60 * 24 * 1000
});
Vue.config.productionTip = false;
/** Function for collapse card */
document.querySelectorAll('[data-toggle="card-collapse"]').forEach(function(card){
card.addEventListener('click', function(evt) {
let $card = this.parentElement.parentElement.parentElement;
let storeId = 'store';
let storeElement = document.getElementById(storeId);
$card.classList.toggle('card-collapsed');
evt.preventDefault();
return false;
Vue.component(
'messageform', {
name: 'MessageForm',
props: {
'imageLabel': {
type: String,
default: "Choisir une image"
},
'uploadClass': {
type: String,
default: "fe fe-upload"
},
'mustencrypt': {
type: Boolean,
default: true
},
'possible': {
type: Boolean,
default: false
}
},
methods: {
encrypt: function(evt) {
evt.preventDefault();
if (this.mustencrypt) {
// https://www.npmjs.com/package/endcrypt
let plain = document.querySelector("[name=message]").value;
document.querySelector("[name=message]").value = JSON.stringify(e.encryptWithKey(plain, this.$storage.get('passphrase')));
}
document.getElementById('messageForm').submit();
return false;
},
fileNameChanged: function(inputName, inputFiles) {
let file = inputFiles[0];
let imageName = file["name"];
if (imageName !== "") {
imageName = imageName.split('\\').pop();
}
if (imageName !== "") {
this.uploadClass = "fe fe-check";
this.imageLabel = imageName;
} else {
this.uploadClass = "fe fe-upload";
this.imageLabel = "Choisir une image";
}
}
},
beforeMount: function() {
let passphrase = this.$storage.get('passphrase', '');
if (passphrase === '') {
passphrase = prompt('Merci d\'entrer votre phrase de passe');
this.$storage.set('passphrase', passphrase);
}
/** Function for collapse and decrypt cards */
let $this = this;
document.querySelectorAll('[data-toggle="card-collapse"]').forEach(function(card){
let cardBody = card.parentElement.parentElement.parentElement.querySelector("[data-encrypt]");
try {
let cardBodyDecrypted = JSON.parse(cardBody.innerHTML.trim());
cardBody.innerHTML = e.decryptWithKey(cardBodyDecrypted, $this.$storage.get('passphrase'));
} catch (e) {
console.log('can\'t decode '+ cardBody.innerHTML);
}
card.addEventListener('click', function(evt) {
let $card = this.parentElement.parentElement.parentElement;
$card.classList.toggle('card-collapsed');
evt.preventDefault();
return false;
});
});
},
components: {
Autocomplete
}
}
);
if (document.getElementById("store")) {
new Vue({
el: '#store'
});
});
let fileNameChanged = function(element, label) {
let labelVal = label.innerText;
let fileName = '';
if (element.value) {
fileName = element.value.split('\\').pop();
}
if (fileName) {
label.firstChild.nextSibling.classList = "fe fe-check";
label.querySelector('.js-fileName').innerHTML = fileName;
} else {
label.firstChild.nextSibling.classList = "fe fe-upload";
label.querySelector('.js-fileName').innerHTML = labelVal;
}
};
let inputFiles = document.querySelectorAll(".input-file");
for (let i = 0, l = inputFiles.length; i < l; i++) {
inputFiles[i].onchange = fileNameChanged.bind(null, inputFiles[i], inputFiles[i].nextSibling.nextSibling);
}
// new Vue();
const app = new Vue({
render: h => h(App),
}).$mount('#app');

View File

@ -1,15 +0,0 @@
<template>
<div>
<Autocomplete hasLabel="false" id="message" name="message" rows="5" placeholder="Que s'est-il passé aujourd'hui ?" textarea="true" />
</div>
</template>
<script>
import Autocomplete from './Autocomplete.vue';
export default {
components: {
Autocomplete
}
}
</script>
<style scoped></style>

View File

@ -28,7 +28,7 @@
props: ["items", "placeholder", "label", "textarea", "rows", "cols", "hasLabel", "name"],
data() {
return {
id: 'input-' + parseInt(Math.random() * 1000, 10),
id: 'input-' + (Math.random() * 1000 | 0),
inputValue: "",
searchMatch: [],
selectedIndex: 0,
@ -51,7 +51,8 @@
}
}
});
let already = document.getElementById("collapse").classList.contains("collapse");
let collapse = document.getElementById("collapse");
let already = collapse && document.getElementById("collapse").classList.contains("collapse");
if (already) {
let post = document.querySelector(".already").innerText;
document.querySelector("textarea").innerHTML = post;
@ -76,7 +77,6 @@
watch: {
inputValue() {
this.focus();
console.log(this.inputSplitted)
this.selectedIndex = 0;
this.wordIndex = this.inputSplitted.length - 1;
}

View File

@ -0,0 +1,26 @@
<MessageForm :mustencrypt="{{ $mustencrypt ? 'true' : 'false' }}" :possible="{{ $possible ? 'true' : 'false' }}" inline-template>
<form action="{{ url('store') }}" method="post" @submit="encrypt" id="messageForm" v-if="possible" enctype="multipart/form-data">
{{ $crsf }}
<div class="contact-form">
<div class="form-group">
<label class="control-label col-sm-5" for="message">Quoi de neuf aujourd'hui ?</label>
<div class="col-sm-10">
<Autocomplete hasLabel="false" id="message" name="message" rows="5" placeholder="Que s'est-il passé aujourd'hui ?" textarea="true" />
</div>
<div class="col-sm-10">
<span class="text-danger"></span>
<input type="file" name="file" id="file" class="input-file" v-on:change="fileNameChanged($event.target.name, $event.target.files)">
<label for="file" class="btn btn-tertiary js-labelFile">
<i v-bind:class="uploadClass"></i>
<span class="js-fileName" v-html:imageLabel="imageLabel"></span>
</label>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<button type="submit" class="btn btn-primary ml-auto">J'enregistre ma journée</button>
</div>
</div>
</div>
</form>
</MessageForm>

View File

@ -80,40 +80,33 @@
<div class="col-md-12">
@if($already)
<div class="alert alert-primary">L'activité du jour a déjà été entrée.</div>
@endif
<div class="row @if($already) collapse @endif" id="collapse">
<div class="col-sm-12">
<div class="card">
<div class="card-header">
<h3 class="card-title">{{ strftime('%B %G', $today->format('U')) }}</h3>
</div>
<div class="card-body">
<form action="@if($already) {{ url('edit') }}@else{{ url('store') }}@endif" method="post" accept-charset="utf-8" enctype="multipart/form-data">
@csrf
<div class="contact-form">
<div class="form-group">
<label class="control-label col-sm-5" for="message">Quoi de neuf aujourd'hui ?</label>
<div class="col-sm-10">
<div id="app"></div>
<span class="text-danger">{{ $errors->first('message') }}</span>
<input type="file" name="file" id="file" class="input-file">
<label for="file" class="btn btn-tertiary js-labelFile">
<i class="fe fe-upload"></i>
<span class="js-fileName">Choose a file</span>
</label>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<button type="submit" class="btn btn-primary ml-auto">J'enregistre ma journée</button>
</div>
</div>
</div>
</form>
<div id="store">
@component('components/app', [
'route' => url('store'),
'crsf' => csrf_field(),
'mustencrypt' => $must_encrypt,
'possible' => false,
])
@endcomponent
</div>
@else
<div class="card">
<div class="card-header">
<h3 class="card-title">{{ strftime('%B %G', $today->format('U')) }}</h3>
</div>
<div class="card-body">
<div id="store">
@component('components/app', [
'route' => url('store'),
'crsf' => csrf_field(),
'mustencrypt' => $must_encrypt,
'possible' => !$already,
])
@endcomponent
</div>
</div>
</div>
</div>
@endif
</div>
@foreach($posts as $post)
<div class="col-md-6 col-xl-4">
@ -134,7 +127,7 @@
</div>
<div class="card-body @if($today->format('Y-m-d') === \Carbon\Carbon::instance($post->date_post)->format('Y-m-d')) already @endif ">
@if($post->image != '')<p><img src="{{ route('display_image', ['post_id' => $post->id, 'options' => 'w:300', 'image_name' => $post->image]) }}"/></p>@endif
{!! $tag_detector->linkTagFrom($post->content) !!}
<p data-encrypt>{!! $tag_detector->linkTagFrom($post->content) !!}</p>
</div>
<div class="card-footer">
{{ \Carbon\Carbon::instance($post->date_post)->format('d F Y') }}