Unverified Commit 4e7bdb92 authored by Nicolas Widart's avatar Nicolas Widart

Merge branch '3.0'

* 3.0:
  Preparing 3.6.0 release
  Adding changelogs
  multiple selector
  Added Image Attribute
  i18nFile & normalFile added two function
  Fixed a bug that checked the last radio even if wasn't the right one
  Pass  to the view
  Add canonical and metadata for pages
  Revert "Add canonical url and alternate links for each language available"
  Add canonical url and alternate links for each language available
  This check if the request page match the locale and the slug. If do not match just do a 301 redirect so the user can see the correct page and the correct url, good for seo purpose.
  In case of accepts json then instead of redirecting sending unauthorised response

# Conflicts:
#	Modules/Core/Foundation/AsgardCms.php
#	Modules/Core/changelog.yml
#	Modules/Media/changelog.yml
#	Modules/Page/changelog.yml
#	Modules/User/changelog.yml
parents 237632e8 b16c521e
......@@ -49,7 +49,7 @@ class Authorization
*/
private function handleUnauthorizedRequest(Request $request, $permission)
{
if ($request->ajax()) {
if ($request->ajax() || $request->wantsJson()) {
return response('Unauthorized.', Response::HTTP_FORBIDDEN);
}
if ($request->user() === null) {
......
......@@ -2,8 +2,11 @@ url: https://github.com/AsgardCms/Platform
versions:
"@unreleased":
added:
- New Hungarian translations
- Laravel 5.6 compatibility
"3.6.0":
added:
- New Hungarian translations
- new <code>i18nFile</code> & <code>normalFile</code> macros
changed:
- Updating Dutch translations
- Fix Carbon locale
......
......@@ -176,6 +176,32 @@ Form::macro('i18nSelect', function ($name, $title, ViewErrorBag $errors, $lang,
return new HtmlString($string);
});
Form::macro('i18nFile', function ($name, $title, ViewErrorBag $errors, $lang, $object = null, array $options = []) {
if (array_key_exists('multiple', $options)) {
$nameForm = "{$lang}[$name][]";
} else {
$nameForm = "{$lang}[$name]";
}
$options = array_merge(['class' => 'form-control'], $options);
$string = "<div class='form-group " . ($errors->has($lang . '.' . $name) ? ' has-error' : '') . "'>";
$string .= "<label for='$nameForm'>$title</label>";
if (is_object($object)) {
$currentData = $object->hasTranslation($lang) ? $object->translate($lang)->{$name} : '';
} else {
$currentData = false;
}
$string .= Form::file("{$lang}[{$name}]",$options);
$string .= $errors->first("{$lang}.{$name}", '<span class="help-block">:message</span>');
$string .= '</div>';
return new HtmlString($string);
});
/*
|--------------------------------------------------------------------------
| Standard fields
......@@ -346,6 +372,25 @@ Form::macro('normalSelect', function ($name, $title, ViewErrorBag $errors, array
return new HtmlString($string);
});
Form::macro('normalFile', function ($name, $title, ViewErrorBag $errors, $object = null, array $options = []) {
$options = array_merge(['class' => 'form-control', 'placeholder' => $title,'multiple'=>'multiple'], $options);
$string = "<div class='form-group " . ($errors->has($name) ? ' has-error' : '') . "'>";
$string .= Form::label($name, $title);
if (is_object($object)) {
$currentData = $object->{$name} ?: '';
} else {
$currentData = null;
}
$string .= Form::file($name,$options);
$string .= $errors->first($name, '<span class="help-block">:message</span>');
$string .= '</div>';
return new HtmlString($string);
});
Response::macro('csv', function ($file, $filename, $status = 200, $headers = []) {
return response($file, $status, array_merge([
'Content-Type' => 'application/csv',
......
<template>
<div>
<label class="el-form-item__label">{{ getFieldLabel() }}</label>
<div class="jsThumbnailImageWrapper jsSingleThumbnailWrapper" v-if="hasSelectedMedia" >
<figure v-for="media in this.selectedMedia" :key="media.id">
<img :src="media.small_thumb" alt="" v-if="media.is_image"/>
<i :class="`fa ${media.fa_icon}`" style="font-size: 60px;" v-if="! media.is_image"></i>
<span v-if="! media.is_image" style="display:block;">{{ media.filename }}</span>
<span class="el-icon-error remove-media" @click="unSelectMedia(media.id)"></span>
</figure>
<div class="clearfix"></div>
</div>
<div>
<el-button type="button" @click="dialogVisible = true">{{ trans('media.Browse') }}</el-button>
</div>
<el-dialog
:visible.sync="dialogVisible"
fullscreen
:before-close="handleClose">
<media-list single-modal :event-name="this.eventName"></media-list>
<span slot="footer" class="dialog-footer">
<el-button @click="dialogVisible = false">{{ trans('core.button.cancel') }}</el-button>
</span>
</el-dialog>
</div>
</template>
<script>
import axios from 'axios';
import UploadZone from '../../../../Media/Assets/js/components/UploadZone.vue';
import MediaList from '../../../../Media/Assets/js/components/MediaList.vue';
import StringHelpers from '../../../../Core/Assets/js/mixins/StringHelpers.vue';
export default {
mixins: [StringHelpers],
props: {
zone: { type: String, required: true },
entity: { type: String, required: true },
entityId: { default: null },
label: { type: String },
},
components: {
'upload-zone': UploadZone,
'media-list': MediaList,
},
watch: {
entityId() {
if (this.entityId) {
this.fetchMedia();
}
},
},
data() {
return {
dialogVisible: false,
selectedMedia: [],
eventName: '',
};
},
computed: {
hasSelectedMedia() {
return this.selectedMedia !== undefined && !_.isEmpty(this.selectedMedia);
},
},
methods: {
handleClose(done) {
done();
},
unSelectMedia(id) {
this.selectedMedia = _.reject(this.selectedMedia, media => media.id === id);
this.$emit('fileUnselected', { id, zone: this.zone });
},
fetchMedia() {
axios.get(route('api.media.get-by-zone-and-entity', {
zone: this.zone,
entity: this.entity,
entity_id: this.entityId,
}))
.then((response) => {
this.selectedMedia = response.data.data;
_.forEach(this.selectedMedia, (file) => {
this.$emit('multipleFileSelected', { id: file.id, zone: this.zone });
});
});
},
getFieldLabel() {
return this.label || this.ucwords(this.zone.replace('_', ' '));
},
makeId() {
let text = '';
const possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
for (let i = 0; i < 5; i++) { text += possible.charAt(Math.floor(Math.random() * possible.length)); }
return text;
},
},
mounted() {
if (this.entityId) {
this.fetchMedia();
}
this.eventName = `fileWasSelected${this.makeId()}${Math.floor(Math.random() * 999999)}`;
this.$events.listen(this.eventName, (mediaData) => {
if (_.find(this.selectedMedia, mediaData) === undefined) {
if (!this.selectedMedia) this.selectedMedia = [];
this.selectedMedia.push(mediaData);
this.$emit('multipleFileSelected', _.merge(mediaData, { zone: this.zone }));
}
});
},
};
</script>
<style>
.remove-media{
position: absolute;
top: 5px;
left: 5px;
color: #FA5555;
}
</style>
\ No newline at end of file
export default {
methods: {
selectMultipleFile(event, model) {
if (!this[model].medias_multi) {
this[model].medias_multi = {};
}
if (!this[model].medias_multi[event.zone]) {
this[model].medias_multi[event.zone] = { files: [] };
}
this[model].medias_multi[event.zone].files.push(event.id);
},
unselectFile(event, model) {
if (!this[model].medias_multi) {
this[model].medias_multi = {};
}
if (!this[model].medias_multi[event.zone]) {
this[model].medias_multi[event.zone] = { files: [] };
if (this.$refs['multiple-media'] !== undefined && this.$refs['multiple-media'].selectedMedia !== undefined && !_.isEmpty(this.$refs['multiple-media'].selectedMedia)) {
_.forEach(this.$refs['multiple-media'].selectedMedia, (file, key) => {
this[model].medias_multi[event.zone].files.push(file.id);
});
}
}
this[model].medias_multi[event.zone].files = _.reject(this[model].medias_multi[event.zone].files, media => media === event.id);
},
},
};
\ No newline at end of file
......@@ -93,6 +93,24 @@ class MediaController extends Controller
return new MediaTransformer($file);
}
/**
* Get a media collection by zone and entity object. Require some params that were passed to request: entity (Full class name of entity), entity_id and zone
*
* @param Request $request
* @return JsonResponse|\Illuminate\Http\Resources\Json\AnonymousResourceCollection
*/
public function getByZoneEntity(Request $request)
{
$entityName = (string)$request->get('entity');
$entityModel = new $entityName;
$entity = $entityModel::find($request->get('entity_id'));
if ($entity && in_array('Modules\Media\Support\Traits\MediaRelation', class_uses($entity)) && $entity->files()->count()) {
$files = $this->file->findMultipleFilesByZoneForEntity($request->get('zone'), $entity);
return MediaTransformer::collection($files);
}
return response()->json(['data' => null]);
}
/**
* Store a newly created resource in storage.
*
......
......@@ -70,6 +70,11 @@ $router->group(['middleware' => 'api.token'], function (Router $router) {
'as' => 'api.media.find-first-by-zone-and-entity',
]);
$router->get('media/get-by-zone-and-entity', [
'uses' => 'MediaController@getByZoneEntity',
'as' => 'api.media.get-by-zone-and-entity',
]);
$router->get('media/{media}', [
'uses' => 'MediaController@find',
'as' => 'api.media.media.find',
......
......@@ -3,6 +3,9 @@ versions:
"@unreleased":
added:
- Laravel 5.6 compatibility
"3.6.0":
added:
- New MediaMuliple component for vuejs projects
"3.5.1":
changed:
- Modify media controller to use Imagy non-statically
......
......@@ -77,4 +77,15 @@ class Page extends Model implements TaggableInterface
#i: No relation found, return the call to parent (Eloquent) to handle it.
return parent::__call($method, $parameters);
}
public function getImageAttribute()
{
$thumbnail = $this->files()->where('zone', 'image')->first();
if ($thumbnail === null) {
return '';
}
return $thumbnail;
}
}
......@@ -38,9 +38,17 @@ class PublicController extends BasePublicController
$this->throw404IfNotFound($page);
$currentTranslatedPage = $page->getTranslation(locale());
if ($slug !== $currentTranslatedPage->slug) {
return redirect()->to($currentTranslatedPage->locale . '/' . $currentTranslatedPage->slug, 301);
}
$template = $this->getTemplateForPage($page);
return view($template, compact('page'));
$alternate = $this->getAlternateMetaData($page);
return view($template, compact('page', 'alternate'));
}
/**
......@@ -54,7 +62,9 @@ class PublicController extends BasePublicController
$template = $this->getTemplateForPage($page);
return view($template, compact('page'));
$alternate = $this->getAlternateMetaData($page);
return view($template, compact('page', 'alternate'));
}
/**
......@@ -95,4 +105,23 @@ class PublicController extends BasePublicController
$this->app->abort('404');
}
}
/**
* Create a key=>value array for alternate links
*
* @param $page
*
* @return array
*/
private function getAlternateMetaData($page)
{
$translations = $page->getTranslationsArray();
$alternate = [];
foreach ($translations as $locale => $data) {
$alternate[$locale] = $data['slug'];
}
return $alternate;
}
}
......@@ -3,10 +3,13 @@ versions:
"@unreleased":
added:
- Laravel 5.6 compatibility
"3.5.2":
"3.6.0":
added:
- Add canonical and metadata for pages
changed:
- Don't show draft pages
- Throw a 404 if page status is disabled
- Fixed a bug that checked the last radio even if wasn't the right one
"3.5.2":
changed:
- Adding support for UTF-8 slug for non ASCII characters (Chinese etc.)
......
......@@ -5,7 +5,7 @@
name="{{ $settingName }}"
type="radio"
class="flat-blue"
{{ isset($dbSettings[$settingName]) && (bool)$dbSettings[$settingName]->plainValue == $value ? 'checked' : '' }}
{{ isset($dbSettings[$settingName]) && $dbSettings[$settingName]->plainValue == $value ? 'checked' : '' }}
value="{{ $value }}" />
{{ trans($optionName) }}
</label>
......
......@@ -6,7 +6,7 @@
name="{{ $settingName . "[$lang]" }}"
type="radio"
class="flat-blue"
{{ isset($dbSettings[$settingName]) && (bool)$oldValue == $value ? 'checked' : '' }}
{{ isset($dbSettings[$settingName]) && $oldValue == $value ? 'checked' : '' }}
value="{{ $value }}" />
{{ trans($optionName) }}
</label>
......
url: https://github.com/AsgardCms/Platform
versions:
"@unreleased":
"3.6.0":
added:
- New <code>@hasSetting()</code> and <code>@endHasSetting</code> directives
- Laravel 5.6 compatibility
......
......@@ -3,6 +3,7 @@ versions:
"@unreleased":
added:
- Laravel 5.6 compatibility
"3.6.0":
changed:
- Adding a test the user token is correctly generated
- Fix creation of an activated user
......
......@@ -3,12 +3,14 @@
<head lang="{{ LaravelLocalization::setLocale() }}">
<meta charset="UTF-8">
@section('meta')
<meta name="description" content="@setting('core::site-description')" />
<meta name="description" content="@setting('core::site-description')"/>
@show
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>
@section('title')@setting('core::site-name')@show
</title>
<title>@section('title')@setting('core::site-name')@show</title>
@foreach($alternate as $alternateLocale=>$alternateSlug)
<link rel="alternate" hreflang="{{$alternateLocale}}" href="{{url($alternateLocale.'/'.$alternateSlug)}}">
@endforeach
<link rel="canonical" href="{{url()->current()}}" />
<link rel="shortcut icon" href="{{ Theme::url('favicon.ico') }}">
{!! Theme::style('css/main.css') !!}
......@@ -30,7 +32,7 @@
@yield('scripts')
<?php if (Setting::has('core::analytics-script')): ?>
{!! Setting::get('core::analytics-script') !!}
{!! Setting::get('core::analytics-script') !!}
<?php endif; ?>
@stack('js-stack')
</body>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment