Finished auto pdf generation
This commit is contained in:
parent
4a3223307c
commit
d2659172f7
257
app/App.php
257
app/App.php
|
@ -13,7 +13,6 @@ use Sikofitt\Config\ConfigTrait;
|
|||
use Sikofitt\Json\JsonFileTrait;
|
||||
use Sikofitt\Json\JsonTrait;
|
||||
use Silex\Application;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
|
||||
require __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
|
@ -33,75 +32,72 @@ class App extends Application
|
|||
use Application\UrlGeneratorTrait;
|
||||
|
||||
private $debug;
|
||||
/**
|
||||
* Returns the application directory.
|
||||
*
|
||||
* @return string
|
||||
* The main application directory.
|
||||
*/
|
||||
public function getAppDirectory()
|
||||
{
|
||||
$r = new ReflectionClass($this);
|
||||
return dirname($r->getFileName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the root directory of the application.
|
||||
*
|
||||
* @return string
|
||||
* The root directory of the application.
|
||||
*/
|
||||
public function getRootDirectory()
|
||||
{
|
||||
return dirname($this->getAppDirectory());
|
||||
}
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getConfDirectory()
|
||||
{
|
||||
return $this->getAppDirectory() . '/config';
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getConfDirectory()
|
||||
{
|
||||
return $this->getAppDirectory() . '/config';
|
||||
}
|
||||
/**
|
||||
* Returns the application directory.
|
||||
*
|
||||
* @return string
|
||||
* The main application directory.
|
||||
*/
|
||||
public function getAppDirectory()
|
||||
{
|
||||
$r = new ReflectionClass($this);
|
||||
return dirname($r->getFileName());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getDataDirectory()
|
||||
{
|
||||
return $this->getRootDirectory() . '/data';
|
||||
}
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getResumeJson()
|
||||
{
|
||||
return $this->getDataDirectory() . '/resume.json';
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getResumeJson()
|
||||
{
|
||||
return $this->getDataDirectory() . '/resume.json';
|
||||
}
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getDataDirectory()
|
||||
{
|
||||
return $this->getRootDirectory() . '/data';
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getResumeSchema()
|
||||
{
|
||||
return $this->getDataDirectory() . '/schema/schema.v1.json';
|
||||
}
|
||||
/**
|
||||
* Returns the root directory of the application.
|
||||
*
|
||||
* @return string
|
||||
* The root directory of the application.
|
||||
*/
|
||||
public function getRootDirectory()
|
||||
{
|
||||
return dirname($this->getAppDirectory());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getResumeSchema()
|
||||
{
|
||||
return $this->getDataDirectory() . '/schema/schema.v1.json';
|
||||
}
|
||||
|
||||
public function getLogDirectory()
|
||||
{
|
||||
return $this->getDataDirectory() . '/logs';
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers media icons
|
||||
*
|
||||
* @param \Sikofitt\Image\Profile\ProfileIconInterface $icon
|
||||
*/
|
||||
public function registerIcon(\Sikofitt\Image\Profile\ProfileIconInterface $icon)
|
||||
{
|
||||
$this->config(sprintf('app.icons.%s', $icon->getName()), ['icon' => $icon->getIcon(), 'url' => $icon->getDefaultUrl()]);
|
||||
}
|
||||
public function getDebug()
|
||||
{
|
||||
return $this['debug'];
|
||||
}
|
||||
|
||||
public function setDebug()
|
||||
{
|
||||
$this['debug'] = (null !== $this->config('app.debug') ? $this->config('app.debug') : true);
|
||||
|
@ -111,77 +107,80 @@ class App extends Application
|
|||
}
|
||||
}
|
||||
|
||||
public function getDebug()
|
||||
{
|
||||
return $this['debug'];
|
||||
}
|
||||
public function registerExtenders()
|
||||
{
|
||||
if (!$this['debug']) {
|
||||
$this->log('In Error handler.');
|
||||
$this->error(function (\Exception $e, \Symfony\Component\HttpFoundation\Request $request, $code) {
|
||||
switch ($code) {
|
||||
case 405:
|
||||
preg_match('/\(Allow\:(.+)\)/', $e->getMessage(), $matches);
|
||||
if (isset($matches[1])) {
|
||||
$matches = trim($matches[1]);
|
||||
} elseif (isset($matches[0])) {
|
||||
$matches = trim($matches[0]);
|
||||
} else {
|
||||
$matches = 'Available methods are unknown.';
|
||||
}
|
||||
$message = [
|
||||
'status' => 'error',
|
||||
'message' => 'Method not allowed',
|
||||
'allowedMethods' => $matches,
|
||||
'requestedMethod' => $request->getMethod(),
|
||||
'code' => $code,
|
||||
];
|
||||
if($request->isXmlHttpRequest()) {
|
||||
$message = json_encode($message);
|
||||
} else {
|
||||
$message = $this->renderView('error.405.html.twig', $message);
|
||||
}
|
||||
$this->log($e->getMessage(), ['code' => $code], \Symfony\Bridge\Monolog\Logger::WARNING);
|
||||
break;
|
||||
case 500:
|
||||
$message = json_encode(['status' => 'error', 'message' => 'Critical Error', 'code' => $code]);
|
||||
$this->log($e->getMessage(), ['code' => $code], \Symfony\Bridge\Monolog\Logger::CRITICAL);
|
||||
break;
|
||||
default:
|
||||
$message = ['status' => 'error', 'message' => $e->getMessage(), 'code' => $code, 'requestUri' => $request->getRequestUri()];
|
||||
if($request->isXmlHttpRequest()) {
|
||||
$message = json_decode($message);
|
||||
} else {
|
||||
$message = $this->renderView('error.html.twig', $message);
|
||||
}
|
||||
|
||||
$this->log($e->getMessage(), ['code' => $code], \Symfony\Bridge\Monolog\Logger::ERROR);
|
||||
break;
|
||||
}
|
||||
|
||||
return new \Symfony\Component\HttpFoundation\Response($message, $code);
|
||||
});
|
||||
}
|
||||
$this->extend('twig', function (\Twig_Environment $twig) {
|
||||
if ($this['debug']) {
|
||||
$twig->enableDebug();
|
||||
}
|
||||
$twig->addExtension(new Twig_Extensions_Extension_Date());
|
||||
$twig->addExtension(new Sikofitt\Twig\Date());
|
||||
$twig->addExtension(new Sikofitt\Twig\RenderProfile());
|
||||
$twig->addGlobal('config', $this->config('all'));
|
||||
return $twig;
|
||||
});
|
||||
}
|
||||
public function boot()
|
||||
{
|
||||
$this->registerExtenders();
|
||||
// register default icons
|
||||
$this->registerDefaultIcons();
|
||||
// register default icons
|
||||
$this->registerDefaultIcons();
|
||||
return parent::boot();
|
||||
}
|
||||
|
||||
public function registerExtenders()
|
||||
{
|
||||
if (!$this['debug']) {
|
||||
$this->log('In Error handler.');
|
||||
$this->error(function (\Exception $e, \Symfony\Component\HttpFoundation\Request $request, $code) {
|
||||
switch ($code) {
|
||||
case 405:
|
||||
preg_match('/\(Allow\:(.+)\)/', $e->getMessage(), $matches);
|
||||
if (isset($matches[1])) {
|
||||
$matches = trim($matches[1]);
|
||||
} elseif (isset($matches[0])) {
|
||||
$matches = trim($matches[0]);
|
||||
} else {
|
||||
$matches = 'Available methods are unknown.';
|
||||
}
|
||||
$message = [
|
||||
'status' => 'error',
|
||||
'message' => 'Method not allowed',
|
||||
'allowedMethods' => $matches,
|
||||
'requestedMethod' => $request->getMethod(),
|
||||
'code' => $code,
|
||||
];
|
||||
if ($request->isXmlHttpRequest()) {
|
||||
$message = json_encode($message);
|
||||
} else {
|
||||
$message = $this->renderView('error.405.html.twig', $message);
|
||||
}
|
||||
$this->log($e->getMessage(), ['code' => $code], \Symfony\Bridge\Monolog\Logger::WARNING);
|
||||
break;
|
||||
case 500:
|
||||
$message = ['status' => 'error', 'message' => 'Critical Error', 'code' => $code];
|
||||
if ($request->isXmlHttpRequest()) {
|
||||
$message = json_decode($message);
|
||||
} else {
|
||||
$message = $this->renderView('error.html.twig', $message);
|
||||
}
|
||||
|
||||
$this->log($e->getMessage(), ['code' => $code], \Symfony\Bridge\Monolog\Logger::CRITICAL);
|
||||
break;
|
||||
default:
|
||||
$message = ['status' => 'error', 'message' => $e->getMessage(), 'code' => $code, 'requestUri' => $request->getRequestUri()];
|
||||
if ($request->isXmlHttpRequest()) {
|
||||
$message = json_decode($message);
|
||||
} else {
|
||||
$message = $this->renderView('error.html.twig', $message);
|
||||
}
|
||||
|
||||
$this->log($e->getMessage(), ['code' => $code], \Symfony\Bridge\Monolog\Logger::ERROR);
|
||||
break;
|
||||
}
|
||||
|
||||
return new \Symfony\Component\HttpFoundation\Response($message, $code);
|
||||
});
|
||||
}
|
||||
$this->extend('twig', function (\Twig_Environment $twig) {
|
||||
if ($this['debug']) {
|
||||
$twig->enableDebug();
|
||||
}
|
||||
$twig->addExtension(new Twig_Extensions_Extension_Date());
|
||||
$twig->addExtension(new Sikofitt\Twig\Date());
|
||||
$twig->addExtension(new Sikofitt\Twig\RenderProfile());
|
||||
$twig->addGlobal('config', $this->config('all'));
|
||||
return $twig;
|
||||
});
|
||||
}
|
||||
|
||||
public function registerDefaultIcons()
|
||||
{
|
||||
$this->registerIcon(new \Sikofitt\Image\Profile\TwitterProfileIcon());
|
||||
|
@ -190,4 +189,14 @@ class App extends Application
|
|||
$this->registerIcon(new \Sikofitt\Image\Profile\GitlabProfileIcon());
|
||||
$this->registerIcon(new \Sikofitt\Image\Profile\LinkedinProfileIcon());
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers media icons
|
||||
*
|
||||
* @param \Sikofitt\Image\Profile\ProfileIconInterface $icon
|
||||
*/
|
||||
public function registerIcon(\Sikofitt\Image\Profile\ProfileIconInterface $icon)
|
||||
{
|
||||
$this->config(sprintf('app.icons.%s', $icon->getName()), ['icon' => $icon->getIcon(), 'url' => $icon->getDefaultUrl()]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,9 +29,9 @@ use Silex\Provider\{
|
|||
VarDumperServiceProvider,
|
||||
WebProfilerServiceProvider
|
||||
};
|
||||
use Symfony\Bridge\Monolog\Logger;
|
||||
use Symfony\Component\Debug\ErrorHandler;
|
||||
use Symfony\Component\Debug\ExceptionHandler;
|
||||
use Symfony\Bridge\Monolog\Logger;
|
||||
use WhoopsPimple\WhoopsServiceProvider;
|
||||
|
||||
$app->register(new ConfigServiceProvider(), [
|
||||
|
@ -57,8 +57,9 @@ $app
|
|||
->register(new LocaleServiceProvider())
|
||||
->register(new TranslationServiceProvider())
|
||||
->register(new ValidatorServiceProvider())
|
||||
->register(new CsrfServiceProvider())
|
||||
->register(new MonologServiceProvider(), [
|
||||
->register(new CsrfServiceProvider());
|
||||
|
||||
$app->register(new MonologServiceProvider(), [
|
||||
//'monolog.logfile' => sprintf('%s/%s.log', $app->getLogDirectory(), $app['env']),
|
||||
'monolog.name' => 'Resume.PHP',
|
||||
'monolog.logfile' => 'php://stderr',
|
||||
|
@ -72,25 +73,25 @@ $app
|
|||
'console.project_directory' => $app->getAppDirectory(),
|
||||
]);
|
||||
$app['swiftmailer.use_spool'] = false;
|
||||
if(false === getenv('SPARKPOST_API_KEY') && null !== $app->config('app.smtp_host')) {
|
||||
$app['swiftmailer.options'] = [
|
||||
if (false === getenv('SPARKPOST_API_KEY') && null !== $app->config('app.smtp_host')) {
|
||||
$app['swiftmailer.options'] = [
|
||||
'host' => $app->config('app.smtp_host'),
|
||||
'port' => $app->config('app.smtp_post'),
|
||||
'username' => $app->config('app.smtp_user'),
|
||||
'password' => $app->config('app.smtp_password'),
|
||||
];
|
||||
$app->log('Setting up local email.');
|
||||
$app->log('Setting up local email.');
|
||||
} elseif (false !== getenv('SPARKPOST_API_KEY')) {
|
||||
$app['swiftmailer.options'] = [
|
||||
$app['swiftmailer.options'] = [
|
||||
'host' => getenv('SPARKPOST_SMTP_HOST'),
|
||||
'port' => getenv('SPARKPOST_SMTP_PORT'),
|
||||
'username' => getenv('SPARKPOST_SMTP_USERNAME'),
|
||||
'password' => getenv('SPARKPOST_SMTP_PASSWORD'),
|
||||
'encryption' => 'tls',
|
||||
];
|
||||
$app->log('Setting up sparkpost email.');
|
||||
$app->log('Setting up sparkpost email.');
|
||||
} else {
|
||||
$app['swiftmailer.transport'] = new Swift_SendmailTransport();
|
||||
$app['swiftmailer.transport'] = new Swift_SendmailTransport();
|
||||
}
|
||||
|
||||
$app->register(new RoutingServiceProvider())
|
||||
|
|
|
@ -31,12 +31,14 @@
|
|||
{% block body %}
|
||||
{% endblock %}
|
||||
</div>
|
||||
{% if renderPdf == false %}
|
||||
<footer id="footer" style="
|
||||
margin-top: 100px;
|
||||
height: 150px;
|
||||
background-color: #000;
|
||||
">
|
||||
</footer>
|
||||
{% endif %}
|
||||
<script src="{{ baseUrl ~ asset('js/resume.min.js') }}"></script>
|
||||
{% block javascripts_foot %}{% endblock %}
|
||||
{% block inline_js_foot %}{% endblock %}
|
||||
|
|
|
@ -0,0 +1,66 @@
|
|||
{% extends 'base.html.twig' %}
|
||||
|
||||
{% block body %}
|
||||
<div class="uk-container uk-container-center">
|
||||
<h1 class="uk-text-center uk-heading-large">{{ basics.name|title }}</h1>
|
||||
<h2 class="uk-text-center">{{ basics.label }}</h2>
|
||||
|
||||
|
||||
{% if basics.summary is defined and basics.summary is not empty %}
|
||||
<p class="uk-text-lead uk-text-center">{{ basics.summary|raw }}</p>
|
||||
{% endif %}
|
||||
|
||||
|
||||
<h2 class="uk-text-center">Contact</h2>
|
||||
<div class="uk-grid uk-grid-match" data-uk-grid-margin="">
|
||||
<div class="uk-width-1-2 uk-row-first">
|
||||
<h3 class="uk-text-center"></h3>
|
||||
</div>
|
||||
<div class="uk-width-1-2">
|
||||
<p class="uk-text-left uk-align-left uk-text-top"></p>
|
||||
</div>
|
||||
</div> <!-- /uk-grid-match -->
|
||||
|
||||
<div class="uk-grid uk-grid-match" data-uk-grid-margin="">
|
||||
<div class="uk-width-1-2 uk-row-first">
|
||||
<h3 class="uk-text-center">Email</h3>
|
||||
</div>
|
||||
<div class="uk-width-1-2">
|
||||
<p class="uk-text-left uk-align-left uk-text-top">{{ basics.email }}</p>
|
||||
</div>
|
||||
</div> <!-- /uk-grid-match -->
|
||||
|
||||
<div class="uk-grid uk-grid-match" data-uk-grid-margin="">
|
||||
<div class="uk-width-1-2 uk-row-first">
|
||||
<h3 class="uk-text-center">Phone</h3>
|
||||
</div>
|
||||
<div class="uk-width-1-2">
|
||||
<p class="uk-text-left">{{ basics.phone }}</p>
|
||||
</div>
|
||||
</div><!-- /uk-grid-match -->
|
||||
|
||||
<div class="uk-grid uk-grid-match" data-uk-grid-margin="">
|
||||
<div class="uk-width-1-2 uk-row-first">
|
||||
<h3 class="uk-text-center">Web</h3>
|
||||
</div>
|
||||
<div class="uk-width-1-2">
|
||||
<p class="uk-text-left">
|
||||
<span class="uk-display-inline-block uk-margin-small-top uk-margin-small-bottom">
|
||||
<a class="profile-link" href="{{ basics.website }}" title="Home page">
|
||||
<span class="uk-margin-small-right">
|
||||
<img class="uk-thumbnail uk-thumbnail-mini uk-border-circle" src="{{ basics.picture }}" alt="Me" />
|
||||
</span>
|
||||
{{ basics.website }}
|
||||
</a>
|
||||
</span><br />
|
||||
{% for profile in basics.profiles %}
|
||||
<span class="uk-display-inline-block uk-margin-small-top uk-margin-small-bottom">{{ render_profile(profile, true)|raw }}</span><br />
|
||||
{% endfor %}
|
||||
</p>
|
||||
</div>
|
||||
</div><!-- /uk-grid-match -->
|
||||
</div>
|
||||
</div><!-- /.uk-container.uk-container-center -->
|
||||
|
||||
{% endblock %}
|
||||
|
|
@ -5,34 +5,28 @@
|
|||
{% endblock %}
|
||||
{% block body %}
|
||||
|
||||
<style type="text/css">
|
||||
.uk-sticky-active-sidebar {
|
||||
margin-top: 35px;
|
||||
}
|
||||
|
||||
div#sidebar.uk-active {
|
||||
margin-top: 35px;
|
||||
transition: margin-top 2s;
|
||||
}
|
||||
</style>
|
||||
<div class="uk-grid" data-uk-grid-margin xmlns="http://www.w3.org/1999/html">
|
||||
<div class="uk-width-1-1">
|
||||
<h1 class="uk-heading-large">
|
||||
{% if basics.name is not empty %}
|
||||
{{ basics.name|title }}
|
||||
{% else %}
|
||||
{{ app.config.app.title|default('Resume') }}
|
||||
{% endif %}
|
||||
{% if basics.label is not empty %}
|
||||
<small class="uk-h2 uk-align-right uk-text-bottom">{{ basics.label }}</small>
|
||||
{% endif %}
|
||||
</h1>
|
||||
<hr/>
|
||||
{% if basics.summary is not empty %}
|
||||
<p class="uk-text-lead">{{ basics.summary|raw }}</p>
|
||||
{% endif %}
|
||||
{% if renderPdf == false %}
|
||||
<div class="uk-width-1-1">
|
||||
|
||||
</div>
|
||||
<h1 class="uk-heading-large">
|
||||
{% if basics.name is not empty %}
|
||||
{{ basics.name|title }}
|
||||
{% else %}
|
||||
{{ app.config.app.title|default('Resume') }}
|
||||
{% endif %}
|
||||
{% if basics.label is not empty %}
|
||||
<small class="uk-h2 uk-align-right uk-text-bottom">{{ basics.label }}</small>
|
||||
{% endif %}
|
||||
</h1>
|
||||
<hr/>
|
||||
{% if basics.summary is not empty %}
|
||||
<p class="uk-text-lead">{{ basics.summary|raw }}</p>
|
||||
{% endif %}
|
||||
|
||||
</div>
|
||||
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<div class="uk-grid" data-uk-grid-margin>
|
||||
|
@ -41,69 +35,81 @@
|
|||
{% include 'work.html.twig' %}
|
||||
{% include 'references.html.twig' %}
|
||||
</div>
|
||||
<div class="uk-width-medium-1-4">
|
||||
<div id="sidebar" class="uk-panel uk-panel-header uk-panel-box"
|
||||
data-uk-sticky="{top:35, animation: 'uk-animation-slide-top', getWidthFrom:'#sidebar'}">
|
||||
<div class="uk-panel-image">
|
||||
<img
|
||||
class="uk-align-right uk-thumbnail uk-border-circle uk-thumbnail-mini uk-animation-scale-up uk-img-preserve"
|
||||
src="{{ basics.picture }}"/>
|
||||
</div>
|
||||
<h3 class="uk-panel-title">Contact</h3>
|
||||
{% if renderPdf == false %}
|
||||
<div class="uk-width-medium-1-4">
|
||||
<div id="sidebar" class="uk-panel uk-panel-header uk-panel-box"
|
||||
data-uk-sticky="{top:35, animation: 'uk-animation-slide-top', getWidthFrom:'#sidebar'}">
|
||||
<div class="uk-panel-image">
|
||||
<img
|
||||
class="uk-align-right uk-thumbnail uk-border-circle uk-thumbnail-mini uk-animation-scale-up uk-img-preserve"
|
||||
src="{{ basics.picture }}"/>
|
||||
</div>
|
||||
<h3 class="uk-panel-title">Contact</h3>
|
||||
|
||||
<ul class="uk-list uk-list-line">
|
||||
<ul class="uk-list uk-list-line">
|
||||
|
||||
{% if app.config.app.phone is not empty %}
|
||||
<li class="uk-list-space"><a href="#phone-modal" class="hidden-phone" data-uk-modal>Phone</a></li>
|
||||
{% endif %}
|
||||
|
||||
<li class="uk-list-space">
|
||||
{% if basics.email is not empty %}
|
||||
<a href="#contact-form-wrapper" data-uk-modal>{{ basics.email }}</a>
|
||||
{% if app.config.app.phone is not empty %}
|
||||
{% if renderPdf == true %}
|
||||
<li class="uk-list-space"><a href="tel:{{ app.config.app.phone }}"
|
||||
title="Telephone">{{ app.config.app.phone }}</a></li>
|
||||
{% else %}
|
||||
<li class="uk-list-space"><a href="#phone-modal" class="hidden-phone" data-uk-modal>Phone</a></li>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
</li>
|
||||
|
||||
{% if basics.website is not empty %}
|
||||
<li class="uk-list-space">
|
||||
<a href="{{ basics.website }}" target="_blank" title="Home page">{{ basics.website }}</a>
|
||||
{% if basics.email is not empty %}
|
||||
{% if renderPdf == true %}
|
||||
<a href="mailto:{{ basics.email }}" title="Send email">{{ basics.email }}</a>
|
||||
{% else %}
|
||||
<a href="#contact-form-wrapper" data-uk-modal>{{ basics.email }}</a>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
</li>
|
||||
{% endif %}
|
||||
{% if basics.location|length > 0 and basics.location is not empty %}
|
||||
|
||||
{% if basics.website is not empty %}
|
||||
<li class="uk-list-space">
|
||||
<a href="{{ basics.website }}" target="_blank" title="Home page">{{ basics.website }}</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
<li><a href="{{ baseUrl ~ asset('pdf') }}" title="Download Resume in PDF format">Download PDF</a></li>
|
||||
{% if basics.location|length > 0 and basics.location is not empty %}
|
||||
<li class="uk-list-space">
|
||||
<address>
|
||||
{% set location = basics.location %}
|
||||
|
||||
{% if location.address is not empty %}
|
||||
{{ location.address }}<br/>
|
||||
{% endif %}
|
||||
{% if location.city is not empty %}
|
||||
{{ location.city }},
|
||||
{% endif %}
|
||||
{% if location.region is not empty %}
|
||||
{{ location.region }},
|
||||
{% endif %}
|
||||
{% if location.countryCode is not empty %}
|
||||
{{ location.countryCode }}
|
||||
{% endif %}<br/>
|
||||
|
||||
</address>
|
||||
</li>
|
||||
{% endif %}
|
||||
<li class="uk-list-space">
|
||||
<address>
|
||||
{% set location = basics.location %}
|
||||
{% for profile in basics.profiles %}
|
||||
{{ render_profile(profile)|raw }}
|
||||
{% endfor %}
|
||||
|
||||
{% if location.address is not empty %}
|
||||
{{ location.address }}<br/>
|
||||
{% endif %}
|
||||
{% if location.city is not empty %}
|
||||
{{ location.city }},
|
||||
{% endif %}
|
||||
{% if location.region is not empty %}
|
||||
{{ location.region }},
|
||||
{% endif %}
|
||||
{% if location.countryCode is not empty %}
|
||||
{{ location.countryCode }}
|
||||
{% endif %}<br/>
|
||||
|
||||
</address>
|
||||
</li>
|
||||
{% endif %}
|
||||
<li class="uk-list-space">
|
||||
{% for profile in basics.profiles %}
|
||||
{{ render_profile(profile)|raw }}
|
||||
{% endfor %}
|
||||
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
{% endif %}
|
||||
</div>
|
||||
{% include 'contact.html.twig' %}
|
||||
|
||||
|
|
|
@ -7,6 +7,5 @@
|
|||
<small>{{ reference.name }}</small>
|
||||
</blockquote>
|
||||
{% endfor %}
|
||||
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
|
|
@ -1,5 +1,18 @@
|
|||
{% if skills is defined and skills is not empty %}
|
||||
|
||||
{% if renderPdf == true %}
|
||||
<div style="position:relative; top:0; left:0;"
|
||||
class="uk-grid uk-width-1-1 uk-grid-match uk-grid-width-1-3 uk-margin-large-top">
|
||||
<div class="uk-text-left">{{ basics.phone }}</div>
|
||||
<div class="uk-text-center">{{ basics.email }}</div>
|
||||
<div class="uk-text-right">{{ basics.website }}</div>
|
||||
</div>
|
||||
<div style="position:absolute; bottom:0; left:0; border-top:1px solid #ddd; padding-top:6px;"
|
||||
class="uk-container uk-container-center uk-grid uk-width-1-1 uk-grid-match uk-grid-width-1-3 uk-margin-large-top">
|
||||
<div class="uk-text-left">{{ basics.phone }}</div>
|
||||
<div class="uk-text-center">{{ basics.email }}</div>
|
||||
<div class="uk-text-right">{{ basics.website }}</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
<h1 id="skills">Skills</h1>
|
||||
<dl class="uk-description-list-line">
|
||||
{% for skill in skills %}
|
||||
|
|
|
@ -45,7 +45,7 @@
|
|||
"startDate": "2007-05-27",
|
||||
"summary": "I have done many different things during my employment at Stanford University.<br />A few of things things have been : Desktop Support, Computer cluster administration for the NSF and NNIN using Scyld Clusterware, General programing/debugging and frontend as well as backend web development using a number of different technologies.",
|
||||
"highlights": [
|
||||
"Repaired and Maintained a 64 node research computing cluster for the <a href=\\\"//nnin.org\\\" title=\\\"National Nanotechnology Infrastructure Network\\\">NNIN</a> funded by the <a href=\\\"//nsf.gov\\\" title=\\\"National Science Foundation\\\">NSF</a>.",
|
||||
"Repaired and Maintained a 64 node research computing cluster for the <a href=\"http://nnin.org\" rel=\"ext\" title=\"National Nanotechnology Infrastructure Network\">NNIN</a> funded by the <a href=\"https://nsf.gov\" rel=\"ext\" title=\"National Science Foundation\">NSF</a>.",
|
||||
"Converted Electrical Engineering's static web site to Drupal 7.",
|
||||
"Created many Drupal 7 modules for the EE website including a custom events, lecture and committe minutes content type, a CDN module for uploading and recieving images/videos/documents, an Orglist module for displaying Faculty, Students, and Staff from a custom API.",
|
||||
"Created a custom Drupal 7 site for the SystemX organization with integrated login for affiliates as well as Stanford staff."
|
||||
|
@ -156,14 +156,5 @@
|
|||
]
|
||||
}
|
||||
],
|
||||
"references": [
|
||||
{
|
||||
"name": "Craig Stadler",
|
||||
"reference": "It is my pleasure to recommend Richard, his performance working as a consultant for Main St. Company proved that he will be a valuable addition to any company."
|
||||
},
|
||||
{
|
||||
"name": "John Doe",
|
||||
"reference": "Richard is awesome and cool."
|
||||
}
|
||||
]
|
||||
"references": []
|
||||
}
|
|
@ -1,4 +1,14 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Resume.PHP.
|
||||
*
|
||||
* (copyleft) R. Eric Wheeler <sikofitt@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: eric
|
||||
|
@ -8,13 +18,14 @@
|
|||
|
||||
namespace Sikofitt\Command;
|
||||
|
||||
|
||||
use Knp\Command\Command;
|
||||
use Knp\Snappy\Pdf;
|
||||
use Sikofitt\Resume\ResumeParser;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Style;
|
||||
use Knp\Snappy\Pdf;
|
||||
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\Process\Process;
|
||||
|
||||
/**
|
||||
* Class CreatePdfCommand
|
||||
|
@ -26,9 +37,9 @@ class CreatePdfCommand extends Command
|
|||
/**
|
||||
*
|
||||
*/
|
||||
public function configure ()
|
||||
public function configure()
|
||||
{
|
||||
$this->setName('resume:pdf:create')
|
||||
$this->setName('resume:pdf:create')
|
||||
->setDescription('Create a pdf of your website.')
|
||||
->setProcessTitle('PDF Creation');
|
||||
}
|
||||
|
@ -37,20 +48,26 @@ class CreatePdfCommand extends Command
|
|||
* @param InputInterface $input
|
||||
* @param OutputInterface $output
|
||||
*/
|
||||
public function interact (InputInterface $input, OutputInterface $output)
|
||||
public function interact(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$index = $this->getSilexApplication()->renderView('index.html.twig', ['renderPdf' => true]);
|
||||
$pdf = new Pdf($this->getSilexApplication()->getRootDirectory() . '/vendor/bin/wkhtmltopdf-amd64');
|
||||
$pdf->generateFromHtml($index, $this->getSilexApplication()->getRootDirectory() . '/resume.pdf', ['keep-relative-links' => false, 'resolve-relative-links' => false, 'load-error-handling' => false, 'disable-javascript' => true, 'disable-external-links' => true, 'disable-internal-links' => true]);
|
||||
$process = new Process('hostname');
|
||||
$process->run();
|
||||
$hostname = $process->getOutput();
|
||||
$resume = new ResumeParser($this->getSilexApplication());
|
||||
|
||||
$request = Request::createFromGlobals();
|
||||
$pdf = new \Sikofitt\Resume\Pdf($this->getSilexApplication(), $request);
|
||||
$pdf->setHost(sprintf('http://%s', $hostname));
|
||||
$data = $pdf->render();
|
||||
|
||||
file_put_contents($this->getSilexApplication()->getRootDirectory() . '/resume1.pdf', $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param InputInterface $input
|
||||
* @param OutputInterface $output
|
||||
*/
|
||||
public function execute (InputInterface $input, OutputInterface $output)
|
||||
public function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -30,27 +30,30 @@ use Symfony\Component\Validator\Constraints\{
|
|||
*
|
||||
* @package Sikofitt\Config
|
||||
*/
|
||||
class ConfigServiceProvider implements ServiceProviderInterface, BootableProviderInterface {
|
||||
class ConfigServiceProvider implements ServiceProviderInterface, BootableProviderInterface
|
||||
{
|
||||
|
||||
/**
|
||||
/**
|
||||
* @param Container $app
|
||||
*/
|
||||
public function register(Container $app) {
|
||||
$app['config'] = function ($app) {
|
||||
public function register(Container $app)
|
||||
{
|
||||
$app['config'] = function ($app) {
|
||||
$config = Config::load($app['config.path']);
|
||||
|
||||
return $config;
|
||||
};
|
||||
}
|
||||
|
||||
public function boot(Application $app) {
|
||||
$configItems = [
|
||||
public function boot(Application $app)
|
||||
{
|
||||
$configItems = [
|
||||
'email' => $app->config('app.email'),
|
||||
'phone' => $app->config('app.phone'),
|
||||
];
|
||||
|
||||
|
||||
$constraints = [
|
||||
$constraints = [
|
||||
'email' => [
|
||||
new NotNull(['message' => 'Email value in app config is not present.']),
|
||||
new NotBlank(['message' => 'Email should cannot be blank in config.']),
|
||||
|
@ -66,30 +69,29 @@ class ConfigServiceProvider implements ServiceProviderInterface, BootableProvide
|
|||
],
|
||||
];
|
||||
|
||||
$captcha = $app->config('app.captcha');
|
||||
if (isset($captcha) && $captcha) {
|
||||
$configItems['captcha_sitekey'] = $app->config('app.captcha_sitekey');
|
||||
$configItems['captcha_secret'] = $app->config('app.captcha_secret');
|
||||
$captcha = $app->config('app.captcha');
|
||||
if (isset($captcha) && $captcha) {
|
||||
$configItems['captcha_sitekey'] = $app->config('app.captcha_sitekey');
|
||||
$configItems['captcha_secret'] = $app->config('app.captcha_secret');
|
||||
|
||||
$constraints['captcha_sitekey'] = [
|
||||
$constraints['captcha_sitekey'] = [
|
||||
new NotNull(['message' => 'ReCaptcha sitekey is a required value to use the captcha, this check can be disabled by removing or setting the captcha config item to false.']),
|
||||
new NotBlank(),
|
||||
new Length(['min' => 40]),
|
||||
];
|
||||
$constraints['captcha_secret'] = [
|
||||
$constraints['captcha_secret'] = [
|
||||
new NotNull(),
|
||||
new NotBlank(),
|
||||
new Length(['min' => 40]),
|
||||
];
|
||||
}
|
||||
$errors = $app['validator']->validate($configItems, new Collection($constraints));
|
||||
$validationErrors = [];
|
||||
foreach ($errors->getIterator() as $error) {
|
||||
$validationErrors[] = $error->getMessage();
|
||||
}
|
||||
if (count($validationErrors) > 0) {
|
||||
throw new MissingConfigurationItemException($validationErrors[0]);
|
||||
}
|
||||
}
|
||||
$errors = $app['validator']->validate($configItems, new Collection($constraints));
|
||||
$validationErrors = [];
|
||||
foreach ($errors->getIterator() as $error) {
|
||||
$validationErrors[] = $error->getMessage();
|
||||
}
|
||||
if (count($validationErrors) > 0) {
|
||||
throw new MissingConfigurationItemException($validationErrors[0]);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,7 +24,6 @@
|
|||
|
||||
namespace Sikofitt\Controller;
|
||||
|
||||
|
||||
use ReCaptcha\ReCaptcha;
|
||||
use Sikofitt\Form\Type\ContactType;
|
||||
use Silex\Api\ControllerProviderInterface;
|
||||
|
@ -44,19 +43,21 @@ use Symfony\Component\Validator\Constraints\Type;
|
|||
*
|
||||
* @package Sikofitt\Controller
|
||||
*/
|
||||
class ApiControllerProvider implements ControllerProviderInterface {
|
||||
class ApiControllerProvider implements ControllerProviderInterface
|
||||
{
|
||||
|
||||
/**
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @param Application $app
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function connect(Application $app) {
|
||||
$controllers = $app['controllers_factory'];
|
||||
public function connect(Application $app)
|
||||
{
|
||||
$controllers = $app['controllers_factory'];
|
||||
|
||||
$controllers->get('/v1/schema', function () use ($app) {
|
||||
$controllers->get('/v1/schema', function () use ($app) {
|
||||
|
||||
$response = new Response(file_get_contents($app->getDataDirectory() . '/schema/schema.v1.json'), Response::HTTP_OK);
|
||||
$response->headers->set('Content-Type', 'application/schema+json');
|
||||
|
@ -64,7 +65,7 @@ class ApiControllerProvider implements ControllerProviderInterface {
|
|||
return $response;
|
||||
});
|
||||
|
||||
$controllers->match('/v1/message', function (Request $request) use ($app) {
|
||||
$controllers->match('/v1/message', function (Request $request) use ($app) {
|
||||
|
||||
static $code = 255;
|
||||
$returnData = [
|
||||
|
@ -121,7 +122,7 @@ class ApiControllerProvider implements ControllerProviderInterface {
|
|||
$valid = $app['validator']->validate($contactFormData, new Collection($constraints));
|
||||
|
||||
if (count($valid) > 0) {
|
||||
$sanitizeProperty = function () use ($valid) {
|
||||
$sanitizeProperty = function () use ($valid) {
|
||||
return str_replace(['][', '[', ']'], [
|
||||
'_',
|
||||
'',
|
||||
|
@ -129,59 +130,55 @@ class ApiControllerProvider implements ControllerProviderInterface {
|
|||
], $valid[0]->getPropertyPath());
|
||||
};
|
||||
|
||||
return new JsonResponse([
|
||||
return new JsonResponse([
|
||||
'status' => 'error',
|
||||
'message' => $valid[0]->getMessage(),
|
||||
'id' => $sanitizeProperty(),
|
||||
'const' => $valid[0]->getCode(),
|
||||
'code' => 256,
|
||||
], 256);
|
||||
|
||||
}
|
||||
else {
|
||||
|
||||
$contactFormName = $contactFormData['contact']['name'];
|
||||
$contactFormEmail = $contactFormData['contact']['email'];
|
||||
$contactFormMessage = sprintf("%s\n\nEmail : %s <%s>", $contactFormData['contact']['message'], $contactFormName, $contactFormEmail);
|
||||
$failures = '';
|
||||
$message = \Swift_Message::newInstance()
|
||||
} else {
|
||||
$contactFormName = $contactFormData['contact']['name'];
|
||||
$contactFormEmail = $contactFormData['contact']['email'];
|
||||
$contactFormMessage = sprintf("%s\n\nEmail : %s <%s>", $contactFormData['contact']['message'], $contactFormName, $contactFormEmail);
|
||||
$failures = '';
|
||||
$message = \Swift_Message::newInstance()
|
||||
->setSubject('[Resume] Message')
|
||||
->setFrom([$app->config('app.from_email') => $contactFormName])
|
||||
->setTo([$app->config('app.email') => 'No-Reply'])
|
||||
->setReplyTo([$contactFormEmail => $contactFormName])
|
||||
->setBody($contactFormMessage);
|
||||
|
||||
$sent = $app['mailer']->send($message, $failures);
|
||||
if ($sent > 0) {
|
||||
$request->getSession()->remove('_csrf/contact');
|
||||
$sent = $app['mailer']->send($message, $failures);
|
||||
if ($sent > 0) {
|
||||
$request->getSession()->remove('_csrf/contact');
|
||||
|
||||
return new JsonResponse([
|
||||
return new JsonResponse([
|
||||
'status' => 'success',
|
||||
'message' => 'Message successfully sent.',
|
||||
'code' => 201,
|
||||
'data' => $contactFormData,
|
||||
'sent' => $sent,
|
||||
], 201);
|
||||
}
|
||||
else {
|
||||
return new JsonResponse([
|
||||
} else {
|
||||
return new JsonResponse([
|
||||
'status' => 'error',
|
||||
'message' => 'There was an error sending the message.',
|
||||
'code' => 255,
|
||||
'failed' => $failures,
|
||||
'sent' => $sent,
|
||||
], 255);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
})->method('POST')->bind('api_message');
|
||||
$controllers->post('/v1/update', function(Request $request) use ($app) {
|
||||
$controllers->post('/v1/update', function (Request $request) use ($app) {
|
||||
|
||||
return new JsonResponse($app->decodeFile($app->getResumeSchema()));
|
||||
})->bind('api_update');
|
||||
|
||||
$controllers->post('/v1/captcha', function (Request $request) use ($app) {
|
||||
$controllers->post('/v1/captcha', function (Request $request) use ($app) {
|
||||
$captcha = new ReCaptcha('6LcvmSQTAAAAAITkvYJjgLar1LqGGLz-ic0ZMiXo');
|
||||
|
||||
$valid = $captcha->verify(
|
||||
|
@ -189,31 +186,30 @@ class ApiControllerProvider implements ControllerProviderInterface {
|
|||
$request->server->get('REMOTE_ADDR')
|
||||
);
|
||||
if ($valid->isSuccess()) {
|
||||
$return = [
|
||||
$return = [
|
||||
'valid' => true,
|
||||
'message' => [
|
||||
'email' => null !== $app->config('app.email') ? $app->config('app.email') : 'No email has been set in the configuration. Please let the owner know.',
|
||||
'phone' => null !== $app->config('app.phone') ? $app->config('app.phone') : 'No phone has been set in the configuration. Please let the owner know.',
|
||||
],
|
||||
];
|
||||
}
|
||||
else {
|
||||
$errorCodes = [
|
||||
} else {
|
||||
$errorCodes = [
|
||||
'missing-input-secret' => 'The secret parameter is missing.',
|
||||
'invalid-input-secret' => 'The secret parameter is invalid or malformed.',
|
||||
'missing-input-response' => 'The response parameter is missing.',
|
||||
'invalid-input-response' => 'The response parameter is invalid or malformed.',
|
||||
];
|
||||
|
||||
foreach ($valid->getErrorCodes() as $code) {
|
||||
if (array_key_exists($code, $errorCodes)) {
|
||||
$errors[] = $errorCodes[$code];
|
||||
foreach ($valid->getErrorCodes() as $code) {
|
||||
if (array_key_exists($code, $errorCodes)) {
|
||||
$errors[] = $errorCodes[$code];
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!isset($errors)) {
|
||||
$errors[] = 'An unknown error occurred.';
|
||||
}
|
||||
$return = [
|
||||
if (!isset($errors)) {
|
||||
$errors[] = 'An unknown error occurred.';
|
||||
}
|
||||
$return = [
|
||||
'valid' => false,
|
||||
'message' => $errors,
|
||||
];
|
||||
|
@ -222,6 +218,6 @@ class ApiControllerProvider implements ControllerProviderInterface {
|
|||
return new JsonResponse(json_encode($return));
|
||||
})->bind('api_captcha');
|
||||
|
||||
return $controllers;
|
||||
return $controllers;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,186 +11,92 @@
|
|||
|
||||
namespace Sikofitt\Controller;
|
||||
|
||||
use ReCaptcha\ReCaptcha;
|
||||
use Sikofitt\Form\Type\ContactType;
|
||||
use Silex\Api\ControllerProviderInterface;
|
||||
use Silex\Application;
|
||||
use Symfony\Component\Form\Form;
|
||||
use Symfony\Component\Form\FormFactory;
|
||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Knp\Snappy\Pdf;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Sikofitt\{
|
||||
Resume\Pdf,
|
||||
Form\Type\ContactType,
|
||||
Resume\ResumeParser
|
||||
};
|
||||
use Silex\{
|
||||
Api\ControllerProviderInterface,
|
||||
Application,
|
||||
ControllerCollection
|
||||
};
|
||||
use Symfony\Component\HttpFoundation\ {
|
||||
Request,
|
||||
Response,
|
||||
ResponseHeaderBag,
|
||||
StreamedResponse
|
||||
};
|
||||
|
||||
/**
|
||||
* Class ResumeControllerProvider
|
||||
*
|
||||
* @package Sikofitt\Controller
|
||||
*/
|
||||
class ResumeControllerProvider implements ControllerProviderInterface
|
||||
{
|
||||
|
||||
/**
|
||||
* @var object
|
||||
*/
|
||||
private $resumeData;
|
||||
* @var ResumeParser
|
||||
*/
|
||||
private $resume;
|
||||
|
||||
/**
|
||||
* @param Application $app
|
||||
* @return mixed
|
||||
*/
|
||||
public function connect(Application $app)
|
||||
{
|
||||
$this->resumeData = $app->decodeFile(
|
||||
$app->getDataDirectory() . '/resume.json',
|
||||
$app->getDataDirectory() . '/schema/schema.v1.json'
|
||||
);
|
||||
/**
|
||||
* @param Application $app
|
||||
*
|
||||
* @return ControllerCollection
|
||||
*/
|
||||
public function connect(Application $app)
|
||||
{
|
||||
$this->resume = new ResumeParser($app);
|
||||
|
||||
$contactForm = $app['form.factory']->create(ContactType::class);
|
||||
$controllers = $app['controllers_factory'];
|
||||
$controllers->get('/pdf', function (Request $request) use ($app) {
|
||||
$pdf = new Pdf($app->getRootDirectory() . '/vendor/bin/wkhtmltopdf-amd64');
|
||||
$content = $app->render('index.html.twig', [
|
||||
'renderPdf' => true,
|
||||
'baseUrl' => $request->getSchemeAndHttpHost(),
|
||||
'fullData' => $this->resumeData,
|
||||
'basics' => $this->getResumeBasics(),
|
||||
'work' => $this->getResumeWork(),
|
||||
'volunteer' => $this->getResumeVolunteer(),
|
||||
'education' => $this->getResumeEducation(),
|
||||
'awards' => $this->getResumeAwards(),
|
||||
'publications' => $this->getResumePublications(),
|
||||
'skills' => $this->getResumeSkills(),
|
||||
'languages' => $this->getResumeLanguages(),
|
||||
'interests' => $this->getResumeInterests(),
|
||||
'references' => $this->getResumeReferences(),
|
||||
]);
|
||||
$controllers = $app['controllers_factory'];
|
||||
|
||||
$renderedPdf = $pdf->getOutputFromHtml($content->getContent());
|
||||
$controllers->get('/', function (Request $request) use ($app) {
|
||||
|
||||
$response = new Response();
|
||||
$response->setContent($renderedPdf);
|
||||
$response->setStatusCode(200);
|
||||
$response->headers->set('Content-Type', 'application/pdf');
|
||||
$response->headers->set('Content-Disposition', 'attachment; filename="resume.pdf');
|
||||
return $response;
|
||||
});
|
||||
$controllers->get('/', function (Request $request) use ($app, $contactForm) {
|
||||
$contactForm = $app['form.factory']->create(ContactType::class);
|
||||
|
||||
return $app['twig']->render('index.html.twig', [
|
||||
'renderPdf' => false,
|
||||
'baseUrl' => $request->getSchemeAndHttpHost(),
|
||||
'basics' => $this->resume->getBasics(),
|
||||
'work' => $this->resume->getWork(),
|
||||
'volunteer' => $this->resume->getVolunteer(),
|
||||
'education' => $this->resume->getEducation(),
|
||||
'awards' => $this->resume->getAwards(),
|
||||
'publications' => $this->resume->getPublications(),
|
||||
'skills' => $this->resume->getSkills(),
|
||||
'languages' => $this->resume->getLanguages(),
|
||||
'interests' => $this->resume->getInterests(),
|
||||
'references' => $this->resume->getReferences(),
|
||||
'contact_form' => $contactForm->createView(),
|
||||
]);
|
||||
});
|
||||
|
||||
$controllers->get('/pdf', function (Request $request) use ($app) {
|
||||
|
||||
$pdf = new Pdf($app, $request);
|
||||
|
||||
$renderedPdf = $pdf->render();
|
||||
|
||||
$filename = str_replace('@', '-AT-', $this->resume->getBasics()->email);
|
||||
|
||||
$response = new StreamedResponse();
|
||||
$response->setCallback(function () use ($renderedPdf) {
|
||||
print $renderedPdf;
|
||||
});
|
||||
|
||||
$response->setStatusCode(Response::HTTP_OK);
|
||||
$disposition = $response->headers->makeDisposition(
|
||||
ResponseHeaderBag::DISPOSITION_ATTACHMENT,
|
||||
$filename . '.pdf'
|
||||
);
|
||||
$response->headers->set('Content-Disposition', $disposition);
|
||||
$response->send();
|
||||
});
|
||||
|
||||
|
||||
return $app['twig']->render('index.html.twig', [
|
||||
'renderPdf' => false,
|
||||
'baseUrl' => $request->getSchemeAndHttpHost(),
|
||||
'fullData' => $this->resumeData,
|
||||
'basics' => $this->getResumeBasics(),
|
||||
'work' => $this->getResumeWork(),
|
||||
'volunteer' => $this->getResumeVolunteer(),
|
||||
'education' => $this->getResumeEducation(),
|
||||
'awards' => $this->getResumeAwards(),
|
||||
'publications' => $this->getResumePublications(),
|
||||
'skills' => $this->getResumeSkills(),
|
||||
'languages' => $this->getResumeLanguages(),
|
||||
'interests' => $this->getResumeInterests(),
|
||||
'references' => $this->getResumeReferences(),
|
||||
'contact_form' => $contactForm->createView(),
|
||||
]);
|
||||
});
|
||||
|
||||
$controllers->post('/', function(Request $request) use ($app) {
|
||||
$contactFormData = $request->request->all();
|
||||
$contactFormName = $contactFormData['contact']['name'];
|
||||
$contactFormEmail = $contactFormData['contact']['email'];
|
||||
$contactFormMessage = $contactFormData['contact']['message'];
|
||||
$sent = $app['mailer']->send(\Swift_Message::newInstance()
|
||||
->setSubject('[Resume] Message')
|
||||
->setFrom([$contactFormEmail => $contactFormName])
|
||||
->setTo($app->config('app.email'))
|
||||
->setBody($contactFormMessage)
|
||||
, $failures);
|
||||
dump($failures);
|
||||
dump($sent);
|
||||
return new JsonResponse(['failures' => $failures, 'sent' => (bool)$sent]);
|
||||
});
|
||||
|
||||
return $controllers;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return null
|
||||
*/
|
||||
public function getResumeBasics()
|
||||
{
|
||||
return (isset($this->resumeData->basics) && count($this->resumeData->basics) > 0) ? $this->resumeData->basics : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return null
|
||||
*/
|
||||
public function getResumeWork()
|
||||
{
|
||||
return (isset($this->resumeData->work) && count($this->resumeData->work) > 0) ? $this->resumeData->work : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return null
|
||||
*/
|
||||
public function getResumeVolunteer()
|
||||
{
|
||||
return (isset($this->resumeData->volunteer) && count($this->resumeData->volunteer) > 0) ? $this->resumeData->volunteer : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return null
|
||||
*/
|
||||
public function getResumeEducation()
|
||||
{
|
||||
return (isset($this->resumeData->education) && count($this->resumeData->education) > 0) ? $this->resumeData->education : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return null
|
||||
*/
|
||||
public function getResumeAwards()
|
||||
{
|
||||
return (isset($this->resumeData->awards) && count($this->resumeData->awards) > 0) ? $this->resumeData->awards : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return null
|
||||
*/
|
||||
public function getResumePublications()
|
||||
{
|
||||
return (isset($this->resumeData->publications) && count($this->resumeData->publications) > 0) ? $this->resumeData->publications : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return null
|
||||
*/
|
||||
public function getResumeSkills()
|
||||
{
|
||||
return (isset($this->resumeData->skills) && count($this->resumeData->skills) > 0) ? $this->resumeData->skills : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return null
|
||||
*/
|
||||
public function getResumeLanguages()
|
||||
{
|
||||
return (isset($this->resumeData->languages) && count($this->resumeData->languages) > 0) ? $this->resumeData->languages : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return null
|
||||
*/
|
||||
public function getResumeInterests()
|
||||
{
|
||||
return (isset($this->resumeData->interests) && count($this->resumeData->interests) > 0) ? $this->resumeData->interests : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return null
|
||||
*/
|
||||
public function getResumeReferences()
|
||||
{
|
||||
return (isset($this->resumeData->references) && count($this->resumeData->references) > 0) ? $this->resumeData->references : null;
|
||||
}
|
||||
return $controllers;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -32,13 +32,12 @@ use Symfony\Component\Validator\Constraints\NotBlank;
|
|||
class ContactType extends AbstractType
|
||||
{
|
||||
|
||||
/**
|
||||
/**
|
||||
* @param FormBuilderInterface $builder
|
||||
* @param array $options
|
||||
*/
|
||||
public function buildForm(FormBuilderInterface $builder, array $options)
|
||||
{
|
||||
|
||||
$builder
|
||||
->setAction('/api/v1/message')
|
||||
->add('name', TextType::class, [
|
||||
|
|
|
@ -0,0 +1,147 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Resume.PHP.
|
||||
*
|
||||
* (copyleft) R. Eric Wheeler <sikofitt@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: eric
|
||||
* Date: 7/17/16
|
||||
* Time: 3:26 PM
|
||||
*/
|
||||
|
||||
namespace Sikofitt\Resume;
|
||||
|
||||
use App;
|
||||
use Knp\Snappy\Pdf as Snappy;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
|
||||
class Pdf
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $host;
|
||||
|
||||
/**
|
||||
* @var Snappy
|
||||
*/
|
||||
private $snappy;
|
||||
|
||||
/**
|
||||
* @var App
|
||||
*/
|
||||
private $app;
|
||||
|
||||
/**
|
||||
* @var Request
|
||||
*/
|
||||
private $request;
|
||||
|
||||
/**
|
||||
* @var ResumeParser
|
||||
*/
|
||||
private $resume;
|
||||
|
||||
/**
|
||||
* Pdf constructor.
|
||||
*
|
||||
* @param App $app
|
||||
* @param Request $request
|
||||
*/
|
||||
public function __construct(App $app, Request $request)
|
||||
{
|
||||
$this->app = $app;
|
||||
$this->request = $request;
|
||||
$this->resume = new ResumeParser($this->app);
|
||||
$this->snappy = new Snappy($app->getRootDirectory() . '/vendor/bin/wkhtmltopdf-amd64');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function render()
|
||||
{
|
||||
$content = $this->getIndex();
|
||||
$cover = $this->getCover();
|
||||
$title = $this->getTitle();
|
||||
|
||||
return $this->snappy->getOutputFromHtml(
|
||||
$content, [
|
||||
'lowquality' => false,
|
||||
'collate' => true,
|
||||
'margin-right' => 1,
|
||||
'margin-left' => 1,
|
||||
'title' => $title,
|
||||
'header-font-size' => 12,
|
||||
'cover' => $cover,
|
||||
'no-stop-slow-scripts' => true,
|
||||
'stop-slow-scripts' => false,
|
||||
'enable-javascript' => true,
|
||||
'no-outline' => true,
|
||||
'outline' => false,
|
||||
'dump-outline' => $this->app->getLogDirectory() . '/pdf-outline-' . md5(time()),
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getIndex()
|
||||
{
|
||||
$host = $this->getHost() ?: $this->request->getSchemeAndHttpHost();
|
||||
|
||||
return $this->app->renderView('index.html.twig', [
|
||||
'renderPdf' => true,
|
||||
'baseUrl' => $host,
|
||||
'basics' => $this->resume->getBasics(),
|
||||
'work' => $this->resume->getWork(),
|
||||
'volunteer' => $this->resume->getVolunteer(),
|
||||
'education' => $this->resume->getEducation(),
|
||||
'awards' => $this->resume->getAwards(),
|
||||
'publications' => $this->resume->getPublications(),
|
||||
'skills' => $this->resume->getSkills(),
|
||||
'languages' => $this->resume->getLanguages(),
|
||||
'interests' => $this->resume->getInterests(),
|
||||
'references' => $this->resume->getReferences(),
|
||||
]);
|
||||
}
|
||||
public function setHost($host)
|
||||
{
|
||||
$this->host = $host;
|
||||
}
|
||||
public function getHost()
|
||||
{
|
||||
return $this->host;
|
||||
}
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getCover()
|
||||
{
|
||||
$host = $this->getHost() ?: $this->request->getSchemeAndHttpHost();
|
||||
return $this->app->renderView('cover.html.twig', [
|
||||
'baseUrl' => $host,
|
||||
'renderPdf' => true,
|
||||
'basics' => $this->resume->getBasics(),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getTitle()
|
||||
{
|
||||
$date = new \DateTimeImmutable('now');
|
||||
$date = $date->format('c');
|
||||
$title = $this->app->config('app.title') ?: 'Resume';
|
||||
return sprintf('%s (%s)', $title, $date);
|
||||
}
|
||||
}
|
|
@ -9,42 +9,283 @@
|
|||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: eric
|
||||
* Date: 7/2/16
|
||||
* Time: 11:22 AM
|
||||
*/
|
||||
|
||||
namespace Sikofitt\Resume;
|
||||
|
||||
use Webmozart\Json\Conversion\JsonConverter;
|
||||
use App;
|
||||
|
||||
/**
|
||||
* Class ResumeParser
|
||||
*
|
||||
* @package Sikofitt\Resume
|
||||
*/
|
||||
class ResumeParser implements JsonConverter
|
||||
class ResumeParser extends \ArrayObject implements \JsonSerializable, \ArrayAccess
|
||||
{
|
||||
/**
|
||||
* @param mixed $jsonData
|
||||
* @param array $options
|
||||
*
|
||||
* @return void
|
||||
* @var
|
||||
*/
|
||||
public function fromJson($jsonData, array $options = [])
|
||||
private $input;
|
||||
/**
|
||||
* @var
|
||||
*/
|
||||
private $basics;
|
||||
/**
|
||||
* @var
|
||||
*/
|
||||
private $work;
|
||||
/**
|
||||
* @var
|
||||
*/
|
||||
private $volunteer;
|
||||
/**
|
||||
* @var
|
||||
*/
|
||||
private $education;
|
||||
/**
|
||||
* @var
|
||||
*/
|
||||
private $awards;
|
||||
/**
|
||||
* @var
|
||||
*/
|
||||
private $publications;
|
||||
/**
|
||||
* @var
|
||||
*/
|
||||
private $skills;
|
||||
/**
|
||||
* @var
|
||||
*/
|
||||
private $languages;
|
||||
/**
|
||||
* @var
|
||||
*/
|
||||
private $interests;
|
||||
/**
|
||||
* @var
|
||||
*/
|
||||
private $references;
|
||||
|
||||
/**
|
||||
* ResumeParser constructor.
|
||||
*
|
||||
* @param App $app
|
||||
* @param int $flags
|
||||
* @param string $iterator_class
|
||||
*/
|
||||
public function __construct(App $app, $flags = 0, $iterator_class = 'ArrayIterator')
|
||||
{
|
||||
// TODO: Implement fromJson() method.
|
||||
$this->app = $app;
|
||||
$this->input = $this->app->decodeFile($app->getResumeJson(), $app->getResumeSchema());
|
||||
|
||||
parent::__construct($this->input, $flags, $iterator_class);
|
||||
$this
|
||||
->setBasics($this->offsetGet('basics'))
|
||||
->setWork($this->offsetGet('work'))
|
||||
->setVolunteer($this->offsetGet('volunteer'))
|
||||
->setEducation($this->offsetGet('education'))
|
||||
->setAwards($this->offsetGet('awards'))
|
||||
->setPublications($this->offsetGet('publications'))
|
||||
->setSkills($this->offsetGet('skills'))
|
||||
->setLanguages($this->offsetGet('languages'))
|
||||
->setInterests($this->offsetGet('interests'))
|
||||
->setReferences($this->offsetGet('references'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $data
|
||||
* @param array $options
|
||||
*
|
||||
* @return void
|
||||
* @return mixed
|
||||
*/
|
||||
public function toJson($data, array $options = [])
|
||||
public function jsonSerialize()
|
||||
{
|
||||
// TODO: Implement toJson() method.
|
||||
return $this->app->encode($this->input, $this->app->getResumeSchema());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getBasics()
|
||||
{
|
||||
return $this->basics;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $basics
|
||||
*
|
||||
* @return ResumeParser
|
||||
*/
|
||||
public function setBasics($basics)
|
||||
{
|
||||
$this->basics = $basics;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getWork()
|
||||
{
|
||||
return $this->work;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $work
|
||||
*
|
||||
* @return ResumeParser
|
||||
*/
|
||||
public function setWork($work)
|
||||
{
|
||||
$this->work = $work;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getVolunteer()
|
||||
{
|
||||
return $this->volunteer;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $volunteer
|
||||
*
|
||||
* @return ResumeParser
|
||||
*/
|
||||
public function setVolunteer($volunteer)
|
||||
{
|
||||
$this->volunteer = $volunteer;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getEducation()
|
||||
{
|
||||
return $this->education;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $education
|
||||
*
|
||||
* @return ResumeParser
|
||||
*/
|
||||
public function setEducation($education)
|
||||
{
|
||||
$this->education = $education;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getAwards()
|
||||
{
|
||||
return $this->awards;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $awards
|
||||
*
|
||||
* @return ResumeParser
|
||||
*/
|
||||
public function setAwards($awards)
|
||||
{
|
||||
$this->awards = $awards;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getPublications()
|
||||
{
|
||||
return $this->publications;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $publications
|
||||
*
|
||||
* @return ResumeParser
|
||||
*/
|
||||
public function setPublications($publications)
|
||||
{
|
||||
$this->publications = $publications;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getSkills()
|
||||
{
|
||||
return $this->skills;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $skills
|
||||
*
|
||||
* @return ResumeParser
|
||||
*/
|
||||
public function setSkills($skills)
|
||||
{
|
||||
$this->skills = $skills;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getLanguages()
|
||||
{
|
||||
return $this->languages;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $languages
|
||||
*
|
||||
* @return ResumeParser
|
||||
*/
|
||||
public function setLanguages($languages)
|
||||
{
|
||||
$this->languages = $languages;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getInterests()
|
||||
{
|
||||
return $this->interests;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $interests
|
||||
*
|
||||
* @return ResumeParser
|
||||
*/
|
||||
public function setInterests($interests)
|
||||
{
|
||||
$this->interests = $interests;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getReferences()
|
||||
{
|
||||
return $this->references;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $references
|
||||
*
|
||||
* @return ResumeParser
|
||||
*/
|
||||
public function setReferences($references)
|
||||
{
|
||||
$this->references = $references;
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -39,7 +39,7 @@ class RenderProfile extends \Twig_Extension
|
|||
];
|
||||
}
|
||||
|
||||
public function renderProfile($context, $iconData)
|
||||
public function renderProfile($context, $iconData, $withText = false)
|
||||
{
|
||||
$imageData = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABkAAAAZCAIAAABLixI0AAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH4AcHEQYsjAFXqQAAAEVpVFh0Q29tbWVudAAAAAAAQ1JFQVRPUjogZ2QtanBlZyB2MS4wICh1c2luZyBJSkcgSlBFRyB2ODApLCBxdWFsaXR5ID0gOTAKqozFDgAAAiVJREFUOMutlT/oOWEcx+8OX5fLDVwx2ZQFSQYzmZgMzCaDzaCUMpmQkowM2G+gFFnUGXRKSQwGIYtyisif+w2n+973ucef4fde7u75fD6v5/l8Ps/zHMLDxHFcp9OJxWJOp1Ov1ysUChzHLRZLNBrt9Xrn8xkahciH6vW6VqtFXouiqOFw+JmVz+eR79Rqtd6xSqUS8rUwDGNZFs7a7/c4jku9lUplOByuVqvtdpum6Xg8jqKo1MHn88FZHo8HmPnn50co8+PxeLVwjuNA1mq1giaSTCaDwaDX653P58+Av6pUKiJLKQxNJhMUReWumUxGeGFZ1mw2yydbLpe/FRQeh8NBDhJFkmQgEEAQJJ1OAyaDwfD7ISyv2+0CdZV2YL1e8zw/Go3UajXQSkjtj8fjK1YkEnmWQ6kETEajUcp65qjRaAqFApRls9kQBBkMBrfbDTBtt9tGowHmKMhqtUJzJAhCpVJBZ9LpdKfTCbLvGYaRe2ez2d1uV6vV5CahLAzDwM9jIpEAAjabDXRnCSqXy5fLBc46HA4kSUq9c7kcz/PQdQElAlnX69XhcHx5vP1+P6SP0i0DnPD3rD+xgPnxeJhMpm9AKIra7faXCYtaLBYURUHjRWEYJnbw5R0t6HK5hEIhKYggiGazOZ1O+/1+u90ej8ef73up3G63yEqlUu+dP7Du97vL5RL+F/wnIR89ZrMZhmHFYvE/sHiep2lavFff6B8xFGrMmf/uPQAAAABJRU5ErkJggg==';
|
||||
//network": "Twitter" +"username": "sikofitt" +"url": ""
|
||||
|
@ -57,7 +57,11 @@ class RenderProfile extends \Twig_Extension
|
|||
}
|
||||
$imageUrl = sprintf('<img src="%s" alt="%s" />', $imageData['icon'], $iconData->network);
|
||||
if (isset($iconData->url) && !empty($iconData->url)) {
|
||||
return sprintf('<a class="profile-link" href="%s" title="%s" target="_blank">%s</a>', $iconData->url, $iconData->network, $imageUrl);
|
||||
if ($withText) {
|
||||
return sprintf('<a class="profile-link" href="%s" title="%s" target="_blank"><span class="uk-margin-small-right">%s</span> %s</a>', $iconData->url, $iconData->network, $imageUrl, $iconData->url);
|
||||
} else {
|
||||
return sprintf('<a class="profile-link" href="%s" title="%s" target="_blank">%s</a>', $iconData->url, $iconData->network, $imageUrl);
|
||||
}
|
||||
} else {
|
||||
return $imageUrl;
|
||||
}
|
||||
|
|
|
@ -77,4 +77,6 @@ jq(document).ready(function (jq) {
|
|||
jq(this).removeClass('uk-form-danger');
|
||||
}
|
||||
});
|
||||
|
||||
jq('a[rel=ext]').attr('target', '_blank');
|
||||
});
|
|
@ -28,6 +28,10 @@ a.profile-link {
|
|||
&:hover {
|
||||
filter: grayscale(0%);
|
||||
}
|
||||
> * img {
|
||||
width:25px;
|
||||
padding:0px;
|
||||
}
|
||||
}
|
||||
|
||||
.uk-panel-image {
|
||||
|
@ -41,6 +45,7 @@ a.profile-link {
|
|||
|
||||
}
|
||||
|
||||
|
||||
.uk-text-lead {
|
||||
font-size: 24px;
|
||||
line-height: 38px;
|
||||
|
@ -63,3 +68,12 @@ a.profile-link {
|
|||
font-size: 34px;
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
.uk-sticky-active-sidebar {
|
||||
margin-top: 35px;
|
||||
}
|
||||
|
||||
div#sidebar.uk-active {
|
||||
margin-top: 35px;
|
||||
transition: margin-top 2s;
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
<IfModule mod_rewrite.c>
|
||||
Options -MultiViews
|
||||
|
||||
RewriteEngine On
|
||||
#RewriteBase /path/to/app
|
||||
RewriteCond %{REQUEST_FILENAME} !-d
|
||||
RewriteCond %{REQUEST_FILENAME} !-f
|
||||
RewriteRule ^ index.php [QSA,L]
|
||||
</IfModule>
|
|
@ -9,7 +9,6 @@
|
|||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
|
||||
require_once __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
# www.robotstxt.org/
|
||||
# www.google.com/support/webmasters/bin/answer.py?hl=en&answer=156449
|
||||
|
||||
User-agent: *
|
||||
Disallow:
|
Loading…
Reference in New Issue